Objective-c – Releasing UIViewController when its view is removed via removeFromSuperview

cocoa-touchiphoneobjective c

I have a main view that manually creates a UIViewController (not a UINavigationController) and adds that controller's view as a subview.

The subview then dismisses itself via [self removeFromSuperview]. I understand this releases the view, so that is good, however I now want to get also get rid of the UIViewController I alloc'ed immediately when the view is removed to free up memory and not wait until the main view controller is dealloc'ed.

I could avoid using removeFromSuperview and have a backreference to the main view controller and get it to dismiss the subview and release the controller, but it feels like there should be a cleaner way.

Is there an established best practice for accomplishing this?

Best Answer

The correct way is for your subcontroller to ask the main controller to remove it. If you want to reduce the coupling between the two controllers, create a delegate protocol for your subcontroller:

// This forward declaration avoids having a circular dependency 
// between MySubcontroller and MySubcontrollerDelegate
@class MySubcontroller;

@protocol MySubcontrollerDelegate

- (void)hideMySubcontroller:(MySubcontroller*)subcontroller;

@end

If there is other information that the subcontroller needs to communicate to the supercontroller, this is a great place to add relevant calls. You might not need to do so right away, but keep it in mind for future versions of your app.

Then add a delegate property to the subcontroller:

@interface MySubcontroller : UIViewController {
    id <MySubcontrollerDelegate> delegate;
    ...
}
@property (assign) id <MySubcontrollerDelegate> delegate;
...
@end

Instead of calling removeFromSuperview on its view, the subcontroller should call hideMySubcontroller: on its delegate, passing self as the argument.

Your main controller should then declare that it implements the delegate protocol:

@interface MyMainController : UIViewController <MySubcontrollerDelegate>
...
@end

When the main controller creates a subcontroller, it should set the subcontroller's delegate property to self. It should implement a hideMySubcontroller: method which removes the subcontroller's view, deallocates the subcontroller, and does whatever else is needed.

Using a delegate protocol means that the subcontroller doesn't have to have any knowledge of what kind of object will use it; it just knows that there is such an object somewhere and that it will conform to the delegate protocol. Thus, the coupling between the two controllers is kept as small as possible.

By the way, if you can manage it, it's actually better to keep the subcontroller around in case you need to use it again; that'll save the processing time it would take to recreate it. (However, you should release it if you receive a memory warning.)

Related Topic