views:

113

answers:

1

Hi I have been doing spring cleaning in my app. I noticed something strange, that, when I tried to correct it, completely crashes my app.

There are two "paths" in my app; either you are in the "A" part of it or you are in the "B" part. From the "A" part you can go to the "B" part and the other way around.

I designed it so that the app delegate class has two methods; switchToAView and switchToBView

So being in the middle of the BView and calling the switchToAView method on the app delegate should completely release everything related to the BView and send the user to the AView.

I found out when switching to the AView the BView view was still retained.

Each view is held by a property.

interface;
@property(nonatomic, retain) UIView *viewA 
@property(nonatomic, retain) UIView *viewB 
implementation;
@synthesize viewA, viewB

in the appDelegate.

I put a breakpoint in the dealloc method of the two views. (viewA and viewB). Now this happens; When loading up viewA and from there switching to viewB, nothing is released(as expected). Then when I switch from viewB to viewA, viewA is first released (by the generated setter, as far as I can figure out). and then viewA is initialized and displayed. This works just fine but has the downside that both viewA and viewB is alive on the stack at the same time :/ this is not desirable as they are mutually exclusive. The viewA is only released when a new viewA comes along, however, viewA should be released when a viewB is added to the window

I then tried releasing the viewA in the switchToBView method. This works fine when going from viewA to viewB. I checked with instruments and the retain count drops to 0 for the viewA. Now when switching back to the viewA, the app crashes, and I think it is because the:

self.viewA = newlyInstantiatedViewA;

setter, first sends a release message to the viewA, but I released viewA earlier, and this causes the crash.

I can't get my head around that using a setter this way, will cause a crash. ("message sent to deallocated instance" and breaking in the dealloc method of the last subview added to A when [super dealloc] is called)

Should I have chosen a different approach all together? And how will I build something sturdy, that ensures only one view is kept alive at a time?

Sorry for the lengthy writing, I would have written less if I had more time: Thanks you in advance for any solution or design suggestions:)

+3  A: 

Should I have chosen a different approach all together?

Quite definitely, you mixed view controller logic into your views and you have views mutually retaining each other in what appears to be a circular reference.

(1) The views should not have logic for loading other view. Loading and unloading views is the function of the view controller. A view should only be concerned with logic immediately relating to the display. It should not even store or manipulate any user data.

(2) View controllers should seldom call other view controllers. The view controller should be concerned with managing the view and reading and writing data from the view to the data modal.

(3) If you need to relate views, use a UINavigation controller. It's not just for strictly visually hierarchal view patterns. Plus you can hide the nav bar so the user never sees it. You need to have a view controller that pushes viewA and when you need viewB, call the nav to pop viewA and push viewB. To the user, it will look like the views are simply swapping our. See the utility flip view for a similar use.

Your app works temporarily because there is nothing in the language or API that prevents you from cramming almost the entire application logic into a view subclass. However, keeping such a design running and reliable is nearly impossible.

TechZen
Hi TechZen. You are of course completely right:)I did this "design" 3 months ago when I had little Cocoa Touch experience. (viewA and viewB are viewControllers and not just views, but your point remains valid). By wrapping it all inside a navigationController I will get all the help (memory management) that I could ever want from the SDK.I have been replaying every scenario in my head and the navController approach takes care of every corner I can paint myself into.My viewA is actually a navController, instantiated in my AppDelegate, so extending that to viewB is a cakewalk.Thank You:)
RickiG