mikeash / MAZeroingWeakRef

Zeroing weak references for retain/release Objective-C
Other
361 stars 56 forks source link

Using a MAZeroingWeakRef with a ViewController causes subviews not to load from nib iOS 4.x #13

Closed rcancro closed 12 years ago

rcancro commented 12 years ago

When using MAZeroingWeakRef with a UIViewController as the target the VC's view's subviews do not get loaded from the nib. This only happens if the MAZeroingWeakRef is created before the VC's viewDidLoad: method is called (for example in the initWithNibName:bundle: method) and you are running iOS 4.x.

I have created a simple example project that will demonstrate this: https://github.com/rcancro/MAZWRTestApp

For a work around I've found that you can either force viewDidLoad: to be called before creating the MAZeroingWeakRef (by doing something like self.view.hidden = NO;) or create an init function for the ViewController that calls through to initWithNibName:bundle: passing in the nib name.

There are more details on the project's github page.

mikeash commented 12 years ago

That's an interesting one. I assume it's because the class name changes, and UIViewController uses the class name to find its nib.

The solution is probably to override -class to pretend that it's really the superclass. I've resisted this, because this sort of secretiveness can make debugging annoyingly hard, but maybe it's time to do it. If you'd like to try, try adding this function to the MAZWR source:

static Class CustomSubclassClass(id self, SEL _cmd)
{
    return GetRealSuperclass(self);
}

Then add a line to CreatePlainCustomSubclass to hook it into the machinery:

class_addMethod(subclass, @selector(classForCoder), (IMP)CustomSubclassClass, method_getTypeEncoding(classForCoder));
rcancro commented 12 years ago

Right, that completely makes sense when it is explained! :)

I added the code you provided, and it worked when I made the slight modification to the line in CreatePlainCustomSubclass:

class_addMethod(subclass, @selector(class), (IMP)CustomSubclassClass, method_getTypeEncoding(classForCoder));    

(I changed the selector from classForCoder to class).

I think for the time being I'll use the work around that I came up with -- to implement the VC's init method and explicitly call initWithNibName:bundle: with the class's name. But it makes me feel a lot better to understand what is going on.

Thanks again for the help and the awesome code!!

mikeash commented 12 years ago

Glad to hear that the workaround worked. Not sure if I want to incorporate it into the code, but it's something to think about. Thanks for reporting the problem.

HiroProt commented 12 years ago

Ran into the same issue...I think we should keep this open until it's actually fixed in the code.

mikeash commented 12 years ago

If more than one person has hit it, that's starting to make a good case to apply the workaround. Can you verify that this workaround fixes your case as well?

HiroProt commented 12 years ago

It did from what I could tell, but your secretiveness && debugging statement made me nervous, so I modified my viewcontroller code to not use MAZeroingWeakRef before the view is loaded, which fixed things as well.