自定义 XIB 的“文件所有者”
Posted
技术标签:
【中文标题】自定义 XIB 的“文件所有者”【英文标题】:"File's Owner" of a custom XIB 【发布时间】:2011-08-25 13:50:08 【问题描述】:如果我创建一个单独的 nib 文件并将其加载到我的视图控制器中并将其分配给 ivar,如下所示:
self.loadingview=[[[NSBundle mainBundle] loadNibNamed:@"loading" owner:self options:nil] objectAtIndex:0];
是否可以为笔尖上的任何东西创建 IBOutlets,比如活动指示器?文件的所有者是否会成为视图控制器,即使 IB 不知道这一点,因为它是在代码中创建的对象?
按照我的方式加载笔尖是可接受的做法吗?
也许更可接受的做法是创建一个 .h/.m,并将其用作 XIB 的类,在这种情况下,File's Owner 是新的自定义类;不过,从自定义类创建 ivar 时,我仍然需要在我的控制器中使用上述方法,对吗?或者有没有更好的方法来完成这一切,而不使用控制器的 xib?
更新:根据一些答案,我做了以下事情。我摆脱了上面的NSBundle
方法,而是这样做:
@property (nonatomic, retain) IBOutlet UIView*loadingview;
在此视图的 nib 文件中,我单击 File's Owner 并将 Custom Class
更改为我的视图控制器。然后我从 File's Owner 控制并拖动到视图,它链接起来很好。
此时我假设我的控制器中有一个 ivar,self.loadingview
,其中包含 nib 中的信息。然而事实并非如此。我删除了 NSBundle 方法,假设控制器现在将直接通过 IB 插座加载 nib,但 nib 中的视图没有显示,并且我无法在控制器中控制它。
我在删除 NSBundle 方法时也删除了这个:
[self.view addSubview:self.loadingview];
我不清楚此时视图的实际显示方式;如果是这样,它出现在视图层次结构中的什么位置?也许它落后于其他观点。我也试过这个:
[self.view bringSubviewToFront:self.loadingview];
但视图并不存在。为了找到它,我做了:
//[self.view bringSubviewToFront:self.loadingview];
NSLog(@"index: %i",[[self.view subviews]indexOfObject:self.loadingview]);
有和没有注释部分。我明白了:
index: 2147483647
【问题讨论】:
问题已解决。我了解到,即使从 nib 加载视图,您仍必须使用addSubview
才能显示它
您的编辑使这个问题完全不同。您应该开始一个新问题,以便以后的搜索者可以找到它。
【参考方案1】:
仅仅因为您创建了一个 nib 并且在该 nib 内部连接了 File's Owner 上的插座并不会自动从您的视图控制器加载该 nib。
您可以为此使用UINib
类:
UINib* nib = [UINib nibWithNibName:@"loading" bundle:[NSBundle mainBundle]];
[nib instantiateWithOwner:self options:nil];
一旦您执行instantiateWithOwner:self
,nib 将被加载,self
将用作文件的所有者,并且 nib 中的视图将连接到您的 loadingView
属性。
您仍然需要调用[self.view addSubview:self.loadingView]
将其添加到屏幕。
【讨论】:
不错。你的博客也不错(我过去曾评论过)。你的方法和写[[NSBundle mainBundle] loadNibNamed:@"loading" owner:self options:nil];
有什么不同
UINib
缓存 nib 对象,因此效率更高。除此之外,可能没有太大区别。【参考方案2】:
Interface Builder 将知道您通过 owner:self
参数发送的文件所有者。要使您的IBOutlet
s 出现在 Interface Builder 中,您需要做的是在 Identity and Type 选项卡下在 IB 中设置文件所有者的正确类。
【讨论】:
我已经根据这些答案更新了我的问题,虽然 IBOutlets 出现并在 IB 中工作,但视图本身似乎无法通过我的控制器的 ivar 进行控制。【参考方案3】:是否可以为笔尖上的任何东西创建 IBOutlets,比如活动指示器?文件的所有者是否会成为视图控制器,即使 IB 不知道这一点,因为它是在代码中创建的对象?
它们不会是 IBOutlets,但是是的,您可以手动进行接线。 IBOutlet
是一个空宏。它专门存在,以便 Interface Builder 可以找到您希望它连接到的属性。但是IBOutlet
关键字对运行时绝对没有影响(编译器甚至看不到它)。类似地,IBAction
是一个被 void
替换的宏。运行时不存在任何关于 Interface Builder 的内容。
当 nib 加载器读取 nib 文件时,它会反序列化每个对象,然后对于每个连接,它会向传递新对象的连接目标发送一个 setter 消息 (setFoo:
)。在为 nib 文件中的每个对象完成该操作后,它会将awakeFromNib
发送给它创建的每个对象。连接目标为nil
的对象将发送给“所有者”(在您的示例中为self
)。请注意,文件所有者不是由 nib 加载程序创建的。 nib 加载器无法控制文件所有者的实际类。您需要确保文件所有者响应 set...:
调用,否则您将崩溃。
按照我的方式加载笔尖是可接受的做法吗?
我不会依赖loadingView
作为第一个***对象。对象的顺序没有定义。相反,您应该使用 IB 将视图连接到文件所有者的 loadingView
属性。
也许更可接受的做法是创建一个 .h/.m,并将其用作 XIB 的类,在这种情况下,File's Owner 是新的自定义类;不过,从自定义类创建 ivar 时,我仍然需要在我的控制器中使用上述方法,对吗?或者有没有更好的方法来完成这一切,而不使用控制器的 xib?
传统的做法是为 ios 中的每个 nib 文件设置一个UIViewController
。但这不是必需的。在 Mac 上,NSViewController
是相当新的,并且不如UIViewController
好用,所以那里没有那么强大的传统。像我所描述的那样手动加载在那里更常见,尽管大多数事情仍然通过NSWindowController
处理。
如果你想做这些事情,需要阅读资源编程指南中的Nib Files。
【讨论】:
我已经根据这些答案更新了我的问题,虽然 IBOutlets 出现并在 IB 中工作,但视图本身似乎无法通过我的控制器的 ivar 进行控制。以上是关于自定义 XIB 的“文件所有者”的主要内容,如果未能解决你的问题,请参考以下文章