0

Usually my code with loading custom view from xib looks like:

@implemenation MyCustomView

- (id)init
{
    [self release];

    if ((self = [[NSBundle loadViewFromXibName:@"MyCustomView" withClass:[MyCustomView class] owner:nil] retain]))
    {
        //some init here
    }

    return self;
}

where [NSBundle loadViewFromXibName:withClass:owner:] - return atoreleased View, loaded from xib.

And all working properly. But when I try write under ARC equivalent code:

@implemenation MyCustomView

- (id)init
{
    if ((self = [NSBundle loadViewFromXibName:@"MyCustomView" withClass:[MyCustomView class] owner:nil]))
    {
        //some init here
    }

    return self;
}

my app crash with EX_BAD_ACCESS (release message sent to deallocated instance) What happens in this case? And how can I solve this problem?

UPDATED This problem only on iOS6 SDK (iOS6 Simulator). On iOS5 SDK and iOS 5 Devices/Simulator all is fine.

UPDATED This problem appear only with table view cells, its deallocated in tableview lifecycle. I implemented static cell builder (what return cell loaded from xib) and moved internal cell initialization to awakeFromNib. Now all working properly.

I don`t understand why this problem should be - "self" is __strong and if I assign it any object it can`t be autoreleased. Is I mistaken?

Killer
  • 9
  • 3
  • loadViewFromXibName == ? – borrrden Nov 26 '12 at 08:09
  • it`s a method from NSBundle category, load and return View (autoreleased) from xib. – Killer Nov 26 '12 at 08:13
  • The posted code is fine. – Nikolai Ruhe Nov 26 '12 at 08:22
  • Traditionally , you would initialize `self` like this: `self = [super init]` which would NOT return an autoreleased object. Here , you return self as an autoreleased object , which is not supposed to happen from an `init` method . `[[Class alloc] init]` is supposed to return a retained object , and that is one of the ( seven , I think) rules that ARC respects. – George Nov 26 '12 at 08:31
  • Yes, I think so. But below ARC I can retain this object. Is where workaround with ARC? – Killer Nov 26 '12 at 08:33
  • See this post: http://stackoverflow.com/questions/863321/iphone-how-to-load-a-view-using-a-nib-file-created-with-interface-builder – pbibergal Nov 26 '12 at 08:36
  • @George: all of that doesn't matter. ARC handles all of that for you correctly. `init` is `ns_returns_retained`, thus the compiler ensures or converts whatever is assigned to `self` to `__strong` before returning. – newacct Nov 26 '12 at 19:18

2 Answers2

-1

I used to do this pattern but after ARC I tried to avoid it by overriding new instead. I don't know why this causes problems but I'm guessing one of two things:

  1. ARC handles the [self release] properly for you in the case of self = [super init...] because of the Cocoa init naming prefix. You won't get the same behavior if you load from nib (or somewhere else)
  2. If you assign something to self that does not come from [super init...], you lose the memory you allocated with [MyCustomView alloc].

I'm inclined to think it's the latter. If you're loading from nib I suggest just do that in a factory method such as new, not from init.

Edit: When you said that this problem is on iOS 6 then I'm pretty sure you are encountering the same problem I had before. When I debugged this I even put a breakpoint inside dealloc. You'll see that it will stop there once every time you call init.

John Estropia
  • 17,040
  • 4
  • 40
  • 48
  • Yes, and it`s expected behavior. Empty object released and new loaded from xib. – Killer Nov 26 '12 at 08:43
  • "If you assign something to self that does not come from [super init...], you lose the memory you allocated with [MyCustomView alloc]." Of course you do. That's the point. We are trying to deallocate the original object and retain the object we get from the other method and return that – newacct Nov 26 '12 at 19:19
-1

Use this instead:

NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"MyCustomClass" owner:nil options:nil];
self = [nibViews objectAtIndex: 0];

//ideally here it would be nice to loop through that array , check which view is member of your class and assign self to that.

in your init method.

Hope this helps.

Cheers!

George
  • 3,981
  • 1
  • 20
  • 30