重写initWithCoder时无限循环

我有一个UIViewController与一些控制器和一些意见。 其中两个视图(Grid Cell)是其他的视图。 我已经从网格单元的文件的所有者,但他们没有自动加载。

所以我尝试覆盖GridCell.minitWithCoder 。 这开始了一个无限循环。

我知道这是可能的只是重写initWithFrame并添加子视图的代码,但这不是我想要的。 我希望能够在界面生成器中移动视图,并让Xcode使用正确的框架初始化视图。

我如何去实现这个?

编辑1

我试图让它在亚历山大的帮助下工作。 这是我现在已经设置的:MainView具有一个Custom类设置为GridCell的UIView。 它在MainView / File的所有者中有一个sockets。

图1

从GridCell.m中删除了所有的init代码,并为我的自定义类设置了一个sockets

图2

图3

虽然MainView仍然不显示GridCell。 没有错误,只有红色开关应该是孤独的,空的空间。 我究竟做错了什么?

我非常接近以编程方式做这个。 我很乐意学习如何与笔尖虽然。

加载笔尖会导致initWithCoder被再次调用,所以如果子类当前没有任何子视图,那么只需要这样做。

 -(id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { if (self.subviews.count == 0) { UINib *nib = [UINib nibWithNibName:NSStringFromClass([self class]) bundle:nil]; UIView *subview = [[nib instantiateWithOwner:self options:nil] objectAtIndex:0]; subview.frame = self.bounds; [self addSubview:subview]; } } return self; } 

加载一个笔尖将导致相应的所有者在一个

  -(id) initWithCoder:(NSCoder *) coder; 

呼叫

因此,你在这种方法coude:

 self = [[[NSBundle mainBundle] loadNibNamed: @"GridCell" owner: self options: nil] objectAtIndex:0]; 

将再次引起initWithCoder方法的调用。 那是因为你再次尝试加载笔尖。 如果你定义了一个自定义的UIView并创build一个nib文件来展示它的子视图,那么你不能仅仅添加一个UIView到另一个nib文件中,把IB中的类名改为你的自定义类,并期待nib加载系统找出它。 你可以做的是以下几点:

您的自定义视图的nib文件需要将“文件所有者”类设置为您的自定义视图类,并且您的自定义类中需要有一个名为“toplevelSubView”的插口连接到自定义视图nib文件中的视图,该视图充当所有子视图的容器。 添加额外的网点到你的视图类,并连接到“文件的所有者”(您的自定义UIView)的子视图。 (请参阅https://stackoverflow.com/a/7589220/925622

编辑好吧,要回答你编辑的问题,我会做以下几点:

转到你想包括自定义视图与它的nib文件布局的nib文件。 不要使它成为自定义视图(GridCell)本身,而是使视图将包含您的网格单元格(例如,gridCellContainer,但它应该是一个UIView)像在initWithCoder中那样在自定义视图中自定义initWithFrame方法:

 - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"GridCell" owner:self options:nil]; self = [nib objectAtIndex:0]; self.frame = frame; } return self; } 

然后,在视图的fileOwner的viewController,你想包括你的自定义视图(gridCellContainer视图的那个)在viewDidLoad例如

 //... GridCell *gridCell = [[GridCell alloc] initWithFrame:self.viewGridCellContainer.bounds]; [self.viewGridCellContainer addSubview:gridCell]; 

现在,应该按照您的预期工作

文件的所有者不会接到电话

  -(id) initWithCoder:(NSCoder *) coder; 

当加载一个xib。

但是, 在xib中定义的每个视图都会被调用

 -(id) initWithCoder:(NSCoder *) coder; 

当加载一个xib。

如果你有一个在xib中定义的UIView(也就是GridCell)的子类,并且试图在你的子类的initWithCoder中加载相同的xib,那么最终会出现一个无限循环。 但是,我不明白用例是什么。

通常你在一个xib中devise你的UIView的子类(即GridCell),然后在视图控制器的xib中使用这个子类。

此外,不能看到一个用例,你的自定义视图将有一个子视图在它的initWithCoder,即

 -(id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { if (self.subviews.count == 0) { UINib *nib = [UINib nibWithNibName:NSStringFromClass([self class]) bundle:nil]; UIView *subview = [[nib instantiateWithOwner:self options:nil] objectAtIndex:0]; subview.frame = self.bounds; [self addSubview:subview]; } } return self; } 

除非您希望能够在其他xib中按需要覆盖其视图层次结构。 哪个国际海事组织假设一个外部依赖(即在另一个xib中定义的层次结构),有点挫败首先有一个可重用的UIView的目的。

请记住,当加载一个xib,将一个实例作为文件所有者传递时,将会设置它的所有IBOutlet。 在这种情况下,你将用GridCell.xib中的任何根视图replace自己(即GridCell),在这个过程中丢失所有的IBOutlet连接。

 - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"GridCell" owner:self options:nil]; self = [nib objectAtIndex:0]; self.frame = frame; } return self; } 

“ 如何实现一个可重用的UIView ”还有一个更详细的post,这个post更详细一点,希望能够清除一些东西。

loadNibNamed ::将调用initWithCoder:

你为什么不遵循这种模式?

 -(id)initWithCoder:(NSCoder *)coder { if (self = [super initWithcoder:coder]) { // do stuff here ... } return self; } 

[super initWithcoder:coder]是否做你想避免的事情?

我有同样的问题,当我试图覆盖initWithsomething方法,我们需要

 -(id)initWithsomething:(Something *)something { if (self = [super initWithsomething:something]) { // do stuff here ... } return self; } 

代替

 -(id)initWithsomething:(Something *)something { if (self = [super init]) { // do stuff here ... } return self; }