Infinite loop when overriding initWithCoder

前端 未结 5 864
臣服心动
臣服心动 2020-12-28 08:54

I have a UIViewController with some controllers and some views. Two of these views (Grid Cell) are other nibs. I\'ve got outlets from the Grid Cells to File\'s

5条回答
  •  时光取名叫无心
    2020-12-28 09:37

    The File's owner will not get a call to

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

    when loading a xib.

    However, every view defined in that xib will get a call to

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

    when loading a xib.

    If you have a subclass of a UIView (i.e. GridCell) defined in a xib and also try to load that same xib in your subclass's initWithCoder, you will end up with an infinite loop. However, I can't see what will the use case be.

    Usually you design your UIView's subclass (i.e. GridCell) in one xib, then use that subclass in a view controller’s xib for example.

    Also, can't see a use case where your custom view will have a subview in it's initWithCoder, i.e.

    -(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;
    }
    

    Unless you want to be able to override its view hierarchy on demand in some other xib. Which IMO assumes an external dependency (i.e. a hierarchy defined in another xib) and kinda defeats the purpose of having a reusable UIView in the first place.

    Bare in mind that when loading a xib, passing an instance as the File's owner, will have all of its IBOutlet(s) set. In that case, you would be replacing self (i.e. GridCell) with whatever the root view in that GridCell.xib is, losing all IBOutlet connections in the process.

    - (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;
    }
    

    There is a more detailed post on "How to implement a reusable UIView." that goes into a bit more detail as well and hopefully clears things up.

提交回复
热议问题