Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Infinite loop when overriding initWithCoder

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 Owner, but they aren't loaded automatically.

So I try to override GridCell.m's initWithCoder. This starts an infinite loop.

I know it's possible to just override initWithFrame and add the subview from code, but this is not what I want. I want to be able to move the view around in Interface Builder and have Xcode initialize the view with the right frame.

How do I go about achieving this?

EDIT 1

I'm trying to get it working with the help of Alexander. This is how I've now got it set up: MainView has UIView with a Custom class set as GridCell. It got an outlet in the MainView/File's Owner.

Pic 1

Removed all init-code from GridCell.m and set up an outlet to my custom class

Pic 2

Pic 3

The MainView don't still display the GridCell though. There's no error, just a lonely, empty space where the red switch should be. What am I doing wrong?

I'm very close to just doing this programmatically. I would love to learn how to this with nibs though.

like image 860
Jon Ramvi Avatar asked Jul 12 '12 10:07

Jon Ramvi


2 Answers

Loading the nib causes initWithCoder to be called again, so you only want to do so if the subclass currently doesn't have any subviews.

-(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;
}
like image 156
Caleb Shay Avatar answered Nov 15 '22 19:11

Caleb Shay


Loading a nib will cause the corresponding owner in a

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

call

Therefore your coude in this method:

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

will cause again a call of the initWithCoder method. That's because you try to load the nib again. If you define a custom UIView and create a nib file to lay out its subviews you can't just add a UIView to another nib file, change the class name in IB to your custom class and expect the nib loading system to figure it out. What you could do is the following:

Your custom view's nib file needs to have the 'File's owner' class set to your custom view class and you need to have an outlet in your custom class called 'toplevelSubView' connected to a view in your custom view nib file that is acting as a container for all the subviews. Add additional outlets to your view class and connect up the subviews to 'File's owner' (your custom UIView). (See https://stackoverflow.com/a/7589220/925622)

EDIT Okay, to answer your edited question I would do the following:

Go to the nib file where you want to include the custom view with it's nib file layouting it. Do not make it to the custom view (GridCell) itself, instead make a view which will contain your grid cell (gridCellContainer for example, but it should be a UIView) Customize the initWithFrame method within your custom view like you did in initWithCoder:

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

And then, in the viewController which is the fileOwner for the view where you want to include your custom view (the one with the gridCellContainer view) do this in viewDidLoad e.g.

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

Now eveything should work as you expected

like image 30
Alexander Avatar answered Nov 15 '22 17:11

Alexander