Why does this init method return an object out of scope?
Using XCode 4.2, base SDK of 4.3, and ARC, I'm trying to load an UIView from a nib (not a UIViewController). I need to not use a UIViewController at all in the process.
After reading this answer to an S.O. question here, it looks like it can be done: How to load a UIView using a nib file created with Interface Builder (The answer by user "MusiGenesis" describes the process)
I created a sub-class of UIView with a single label:
@interface MyView : UIView
@property (unsafe_unretained, nonatomic) IBOutlet UILabel *textLabel;
@end
In the implementation I override initWithFrame:
- (id)initWithFrame:(CGRect)frame
{
//self = [super initWithFrame:frame];
self = [JVUIKitUtils initWithNibName:@"MyView" withOwner:self];
if( self )
{
NSLog(@"Created");
}
return self;
}
In I.B. I created a file named "MyView.xib" with a single view. It has a label as a sub-view, and I created the label property by dragging it to the h file.
And in another file, I created this re-usable static method:
+ (id)initWithNibName:(NSString*)nibName withOwner:(id)uiView
{
id object = nil;
NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:nibName owner:uiView options:nil]; // 1 object, out of scope
for( id tempObject in bundle)
{
if( [tempObject isKindOfClass:[uiView class]] ) object = tempObject;
break;
}
return object;
}
As you can see in the following screen shot, the bundle has one object reference, but it's out of scope.
And debugging:
This is my code for instantiation:
subView = [[MyView alloc] initWithFrame:CGRectZero]; // ok
NSAssert(subView != nil, @"MyView was nil"); // fail
Any ideas on why the other S.O. poster was able to get it to work but this does not?
Your
[JVUIKitUtils initWithNibName:@"MyView" withOwner:self]
approach is all wrong. When an init method is called, the object is already allocated by the call to[MyView alloc]
. The reason why you chain the calls to the super init method is so that this will daisy chain all the way down to the NSObject init method, which simply returns the instance it is.By setting "self" to the (autoreleased) instance value returned by your
JVUIKitUtils
, you are effectively setting it to a memory address other than what was allocated by the call to[MyView alloc]
, which generates the out of scope error.Instead, don't create the init method your are trying to create. You already have the method to create and initialize your nib-based view in your state method. I would change the name and do something like:
and then call it like:
I haven't tested this code. Your milage might vary.
The use of the owner seems a bit confusing in the way that you are loading a nib. It appears that you are trying to use the view as both the owner of the nib and the first object in it.
Are you trying to load MyView from your nib (i.e. is the class of the view inside your nib files defined as MyView) or are you trying to load a subview of MyView from the nib?
If the view inside your nib is a MyView, here's how to load it. Create this static method as a category on UIView:
That will let you load any kind of view from a nib file (the view needs to be the first item defined in the nib). You would create your view like this:
If the view inside the nib is not a MyView, but you want to load it as a subview of MyView, with MyView defined as the file's owner in the nib file, do it like this:
Using that approach, just create your view as normal using initWithFrame, then call loadContentsFromNibName to loa the contents from a nib. You would load your view like this: