2014-01-10 98 views
2

根据Apple's documentation,Interface Builder实例化对象,然后在设计时将对象序列化并打包到NIB/XIB文件中。在运行时,整个对象图通过initWithCoder:进行反序列化。Interface Builder编码

这里的文档:

认为是在Interface Builder创建不叫initWithFrame实例:当他们的笔尖文件被加载,这往往会导致混乱。请记住,Interface Builder在保存一个nib文件时存档一个对象,所以视图实例已经被创建并且initWithFrame:已经被调用。

作为对象通过的initWithCoder实例:,我认为对象图是通过其对应encodeWithCoder序列:。然而,考虑下面的代码:

@interface CustomView : UIView 
@end 

@implementation CustomView 

-(id)initWithCoder:(NSCoder *)aDecoder{ 
    if(self = [super initWithCoder:aDecoder]){ 
     NSNumber * n = [aDecoder decodeObjectForKey:@"DummyKey"]; 
     NSLog(@"%@", n); 
    } 
    return self; 
} 

-(void)encodeWithCoder:(NSCoder *)aCoder{ 
    [super encodeWithCoder:aCoder]; 
    [aCoder encodeObject:@YES forKey:@"DummyKey"]; 
} 

@end 

如果我把这个CustomView在Interface Builder的故事板,它打印代替“YES” “(空)”。这是为什么发生? Interface Builder如何序列化对象图?我误解了文档?

+0

请注意,您可以在IB中添加“用户定义的运行属性”(选择视图并转至检查器的第三个选项卡)。当它被取消存档IIRC(使用你的属性的setter方法)时,这些将被设置在你的对象上。 – Taum

回答

0

encoderWithCoder:方法不会被调用,因为XCode将对象图编码到xib中的时间不是运行时间,它不能调用您的encoderWithCoder:方法。

How does Interface Builder serialize the object graph?

如果打开厦门国际银行作为源代码,你可以看到它是这样的:

<?xml version="1.0" encoding="UTF-8" standalone="no"?> 
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="4514" systemVersion="13B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none"> 
    <dependencies> 
     <deployment defaultVersion="1536" identifier="iOS"/> 
     <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3747"/> 
    </dependencies> 
    <objects> 
     <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="EMXibViewController"> 
      <connections> 
       <outlet property="view" destination="1" id="3"/> 
      </connections> 
     </placeholder> 
     <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> 
     <view contentMode="scaleToFill" id="1"> 
      <rect key="frame" x="0.0" y="0.0" width="320" height="568"/> 
      <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> 
      <subviews> 
       <view contentMode="scaleToFill" id="XyJ-CF-vRx"> 
        <rect key="frame" x="68" y="102" width="204" height="403"/> 
        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> 
        <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/> 
       </view> 
      </subviews> 
      <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> 
      <simulatedStatusBarMetrics key="simulatedStatusBarMetrics"/> 
      <simulatedScreenMetrics key="simulatedDestinationMetrics" type="retina4"/> 
     </view> 
    </objects> 
</document> 

我们可以看到,厦门国际银行只保留对象的非默认值之间的关系他们。

的厦门国际银行的UIViewController中,有只有两个UI对象,一个是UIViewController的观点,另一个是它的子视图让我们说这mysubview和有关会谈如何XCode的存档mysubview

我已经改变其的backgroundColor,帧和mysubview autoresizingMask属性,采取backgroundColor属性作为例子,backgroundColor属性被保存为“彩色键=”的backgroundColor“白色=‘0.0’阿尔法=‘1’色彩空间=” calibratedWhite “”。它将归档mysubview的backgroundColor。

Xib只是归档了mysubview对象的backgroundColor和autoresizingMask和frame属性,当加载xib时,它会调用UIView的initWithCoder方法。在该方法中,它将获得用于关键字@“backgroundColor”的UIColor对象和用于关键字@“frame”的CGRect以及用于关键字“@ autoresizingMask”的UIViewAutoresizing,而UIView的任何其他属性都被分配了默认值。

- (id)initWithCoder:(NSCoder *)aDecoder 
{ 
    self = [super initWithCoder:aDecoder] ; 
    UIColor * backgroundColor = [aDecoder decodeIntegerForKey:@"backgroundColor"] ; 
    if (backgroundColor) { 
     self.backgroundColor = backgroundColor ; 
    } else { 
     self.backgroundColor = $(defaultColor) ; // if no key in xib, use the default value. 
    } 
    // more... 
    return self ; 
} 

这是一个不错的问题,让我多想一想。

+0

@TamásZahola我已经更新了我的答案,也许更清楚。 – KudoCC

0

Interface Builder不会使用您的代码来生成xib。就这么简单。 Interface Builder不会调用encodeWithCoder。 Interface Builder不运行您的代码。

+0

那么为什么苹果文档会说以下内容:*“请记住,Interface Builder在保存一个nib文件时存档一个对象,所以视图实例已经创建并且initWithFrame:已经被调用。”*? 它明确指出视图通过* initWithFrame:*实例化,然后存档到NIB中。 –

+0

@TamásZahola请注意,Interface Builder不会创建自己的类实例。如果您从库中选择了“UIView”,并将其类更改为“MyView”,则不会创建“MyView”。它仍然只是界面生成器的'UIView'。界面生成器不运行您的代码。 – Sulthan

0

在简单的一句话,如果你创建的厦门国际银行或Storybord你的对象,然后initWithFrame的initWithCoder将无法​​通过您覆盖,他们将通过框架调用,并从厦门国际银行或Storybord创建对象属性。