0

I inherited a code base and found the compiler complaining about this piece of code:

- (id)initWithFrame:(CGRect)frame {
// is this really missing??
// self = [super initWithFrame:frame];
    self = [[[NSBundle mainBundle] loadNibNamed:@"DigitsKeyboardView" owner:self options:nil] firstObject];
    return self;
}

XCode complains that the designated initializer in the super class is not called. If I uncomment the call to super, the error goes away obviously. But as the application did not bother that the line is missing for quite some iOS versions, I am unsure whether this is rather an academic requirement, or may even be wrong in this case.

The loadNibNamed method is called with a self and that self is then overwritten. Could this cause trouble not visible immediately?

What is the proper implementation in a case like this?

codewitharefin
  • 1,398
  • 15
  • 24
thst
  • 4,592
  • 1
  • 26
  • 40

1 Answers1

2

initWithFrame - Initializes and returns a newly allocated view object with the specified frame rectangle. The frame rectangle for the view, measured in points. The origin of the frame is relative to the superview in which you plan to add it. This method uses the frame rectangle to set the center and bounds properties accordingly.

Parameter is frame - The frame rectangle for the view, measured in points. The origin of the frame is relative to the superview in which you plan to add it. This method uses the frame rectangle to set the center and bounds properties accordingly.

So You should call below like this

- (id)initWithFrame:(CGRect)frame 
{
  self = [super initWithFrame:frame];
  if (self) 
  {
    // Initialization code
    NSArray *arrNibView = [[NSBundle mainBundle] loadNibNamed:@"DigitsKeyboardView" owner:self options:nil];
    UIView  *nibView = (UIView*)[arrNibView objectAtIndex:0]; //Give here your first object
    [self addSubview:nibView];
  }
  return self;
}

If you have multiple custom views and If you want to use the custom view for separate controller you can use above method.

But If you have custom view and If you want to use(Reuse) multiple times in multiple view controllers,you need to implement bot both the initWithFrame and awakeFromNib method

- (id)initWithFrame:(CGRect)frame 
{
  self = [super initWithFrame:frame];
  if (self) 
  {
    // Initialization code
    [[NSBundle mainBundle] loadNibNamed:@"DigitsKeyboardView" owner:self options:nil];
    [self addSubview:self.view];
  }
  return self;
}
- (void) awakeFromNib
{
   [super awakeFromNib];
   [self addSubview:self.view];
}

initWithFrame - It is recommended that you implement this method. You can also implement custom initialization methods in addition to, or instead of, this method.

awakeFromNib - awakeFromNib gets called after the view and its subviews were allocated and initialized. It is guaranteed that the view will have all its outlet instance variables set.

Detailed Explanation of awakeFromNib

During the instantiation process, each object in the archive is unarchived and then initialized with the method befitting its type. Cocoa views (and custom views that can be customized using an associated Interface Builder palette) are initialized using their initWithCoder: method. Custom views are initialized using their initWithFrame: method. Custom classes that have been instantiated in the nib are initialized using their init method.

Once all objects have been instantiated and initialized from the archive, the nib loading code attempts to reestablish the connections between each object’s outlets and the corresponding target objects. If your custom objects have outlets, an NSNib object attempts to reestablish any connections you created in Interface Builder. It starts by trying to establish the connections using your object’s own methods first. For each outlet that needs a connection, the NSNib object looks for a method of the form setOutletName: in your object. If that method exists, the NSNib object calls it, passing the target object as a parameter. If you did not define a setter method with that exact name, the NSNib object searches the object for an instance variable (of type IBOutlet id) with the corresponding outlet name and tries to set its value directly. If an instance variable with the correct name cannot be found, initialization of that connection does not occur. Finally, after all the objects are fully initialized, each receives an awakeFromNib message.

Apple Documents

UIView

initWithFrame

awakeFromNib

Other Sources

Getting Nib File loaded

Initialize a view with xib

awakeFromNib Calling

viewDidLoad and awakeFromNib timing

Community
  • 1
  • 1
user3182143
  • 9,459
  • 3
  • 32
  • 39
  • Thank you for the detailed explanation. I found the correct way to implement it in the source of the duplicate question, the comment pointed to. What I am missing from your answer is in fact the consequences when I return the subview as `self`. As it has been working for years now, I suspect, there is not much of an issue for iOS. I suppose, that we loose connection with the initially allocated view and maybe there is an object created that is nowhere stored and removed by ARC after leaving the initWithFrame method. As it was implemented, it is a kind of expensive wrapper around `loadFromNib`. – thst Jul 11 '16 at 12:47