cocoa - quickly release all IBOUtlets - iphone

I have a view with many retained IBOutlets, loaded from a XIB.
I have read that they have to be released when the controller's dealloc method is called.
May I use a cycle to do this(also to avoid releasing each outlet separately)?
something like
for(UIView *v in self.view.subviews){
[v release];
v=nil;
}
?
also, after that, should I release the view as well?

That would only make sense if you've actually retained every single subview, and even then it seems like asking for trouble -- if you ever wanted to change your .xib, you'd have to remember to update you code as well. And there may also be non-view objects in a nib that can be connected to outlets, like view controllers.
There are only so many views you can fit on an iPhone- or iPad-sized screen, so it's hard to imagine that you have more than a few dozen outlets. I think the prudent thing to do here is to simply release each one separately. This is what and iOS developer would expect to see, and it won't be any slower than using a loop. It'll be more code, yes, but the code will be easy to understand.

self.view is automatically released on UIViewController deallocation, and subviews also, if not retained by your code.
You should re-read the chapter on memory management in Apple Documentation... ;)

I wrote like a releaseVars function, which takes address of variables, release them and set to nil. This save some lines of code, but still you have to manually take care of them.

Related

Timing for add Notification observer in UIViewController subclass

I'm fairly new to Cocoa Touch. Right now I'm trying to subclass UIViewController to provide my custom view. Since I intend to save the content of a UITextField (passcodeField) using NSUserDefaults, I want to be notified whenever the UITextField changes its value.
I've read somewhere that in order to do that I should add the view controller to be an observer of the UITextFieldTextDidChangeNotification notification. However I'm just not sure when to do that. I've considered several options.
In the -loadView method. However, since I'm loading my view using a XIB, I think i shouldn't mess with this method and should instead leave it as-is. (Am I correct on this point, BTW? )
In the -viewWillAppear method. But this method may be called multiple times because the view may be moved out and into the screen without being destroyed and recreated. (Am I correct? ) This will not do any harm to the program but sure doesn't seem like the correct way.
In the initializer of the UIViewController. If I want to add the notification there I must reference the UITextField. By doing this I essentially cause the view to created before it is really needed. Also I think I read somewhere that if the system runs low on memory the offscreen views may be destroyed. Thus I may lose the notification observing if such thing happens, right?
So I'm totally confused right now. Could you guys give me some advice of where to put it? Thanks so much!
Put it in the - (void)viewDidLoad method of your ViewController remember to call [super viewDidLoad]; at the start of your implementation.

How to release a view when it's not visible in a tabbar controller?

I have a simple app with a tabbar navigation interface.
It has three view (A, B and C) and a modal view. Each view has its own view controller and nib . They are all designed and connected in the interface builder.
I'd like to release views which are not visible.
Tried release and nil them when another view appears such as
[[[self.navigationController.viewControllers objectAtIndex:0] view] release];
[[self.navigationController.viewControllers objectAtIndex:0] view] = nil;
etc.
It doesn't cause any issues but when I run instruments it does not make any difference. I don't see any drop in memory usage
I would appreciate your help
as #Daryl Teo wrote you should release and recreate in viewWillDis/Appear and (thats why I write this answer) you have a method called didReceiveMemoryWarning, use it!
You can simply log out whenever it gets called and test it with the Simulator included memory warning test function.
Simply open a tab, open another tab and call that test function. Your debug console should print out the log. If not you should double check if you have released all objects maybe someone is over-retained (which again should be released in viewWillDisappear).
The drop in memory usage might not be significant, depending on what the released viewController holds on to. I sugest you out a NSLog into the 'dealloc' of the viewController to see if it really gets dealloced or if there is some other object still holding on to it. Remember that release won't free the memory, it will only do so (by calling dealloc) if the objects retain count reached 0.
You don't want to do this. Let the TabBarController handle your view controllers for you. (It will already retain your viewController internally so whatever you do will only make retain count go out of sync)
You may be able to make it more memory efficient if you release objects in viewWillDisappear. Then rebuild the data again in viewWillAppear.

iPhone Dev Objective-C - Object is being retained and I don't know where

I'm creating an iPad game that has a viewController that loads in its view from a nib file. The view has a bunch of buttons in it, which I linked up to UIButton * variables via interface builder (so each button is linked to a different variable). I checked the retain count right after they nib was loaded on one of the buttons (using my first button variable, b1) and it gives me a value of 2. Can anyone explain why it's 2? What are the two things that are retaining it right after the nib loads?
And now I'm even more confused because in my dealloc function, I released each of the button variables individually, and checked the retain count for one of them after and it's STILL 2! It should at least have gone down to 1, shouldn't it have? Should I release it several times in my dealloc function? If so, how many?
Thanks
Don't look at retain count.
Seriously.
Things other than you retain your stuff. Those numbers will move around underneath you for reasons that appear to make no sense, and then you'll come back here and post bewildered questions.
Just make sure your retains and releases balance. That's your only job.
If your IBOutlet properties are retained then you would have 1 retain there and another when the button gets added to the super view...
As Dan Ray says though, you shouldn't really worry about the retainCount...

Is there a leak in the Scroll View Suite sample code by Apple?

I need help with the code from Apple's ScrollViewSuite; specifically I'm looking at the ThumbImageView class, which doesn't have a dealloc method defined. I see in the .h that the property for imageName uses retain.
(I wasn't sure if I was allowed to post any code since it's Apple's, so please let me know if I can/should.)
Anyway, I thought if we use "retain" that we are responsible for releasing the object reference.
The method CreateThumbScrollViewIfNecessary (from the RootViewController implementation file) has a for loop which allocs ThumbImageViews, sets the delegate, and then after adding the thumbview as a subview the a scrollview, proceeds to release the thumbview. If these objects are actually being released, how does the delegate do its job notifying when an image has been tapped, scrolled, etc.
Sorry I'm just so confused. Any help would be greatly appreciated.
The code leaks. Unfortunately, Apple’s sample code usually leaves a lot to be desired, the design often sucks and there are leaks and glitches. It’s best to take it only as an annotated API reference that shows how various parts of the API fit together, nothing more.
You are responsible for clearing the object reference. As far as I can tell, that code of Apple's would leak if that property were ever assigned a value.
Any view retains its subviews. After each view has been added to the scrollview, the class that creates it has no more use for it so it releases its reference. The object won't actually be deallocated until the scrollview also releases its reference, so the views remain "live" and able to signal their delegates until that happens.

ViewWillDisappear versus dealloc

I put an NSlog in my dealloc method of my view controller. It does not get consistently called. I do notice that ViewWillDisappear does get called always. Would it be ok to move all my tidy upcode here? Setting stuff to Nil and release calls.
Anybody got some advice on why dealloc is not getting called? I know it says in docs it may not get called, but if you have a very simple App it gets called always. So something i do must be affecting the dealloc.
This is the code that calls my ViewController than isnt always calling my dealloc.
-(IBAction) playComputerTapped:(id)sender
{
PlayGameViewController *pgvc = [[PlayGameViewController alloc]
initWithNibName:#"PlayGameViewController" bundle:[NSBundle mainBundle]];
pgvc.gameMode = 1;
[self presentModalViewController:pgvc animated:YES];
[pgvc release];
}
The above code takes me from the mailmenu ViewController into the game.
Below is the code to leave the gameViewController and take me back to the menu.
[self.parentViewController dismissModalViewControllerAnimated:YES];
Thanks
-Code
Don't you mean viewDidUnload instead of viewWillDisappear ?
viewWillDisappear is called when the view controller is disappearing. This usually happens when the view controller is being popped out, or other view controller is pushed to the stack. Purpose of viewWillDisappear is to stop active actions - for example stop animations, hide some elements or similar.
viewDidUnload is probably what you meant as this one is called when view controller's view is unloaded. This should never happen for a view controller that is currently visible, only for controllers that are somewhere in the navigation stack (part of UITabBarController or UINavigationController), but not currently visible. Purpose of viewDidUnload is to release any UI elements that are part of the view and that the view controller retained as well.
To understand it's important to realize the reasons why a view for such controller would want to be unloaded. Reason is memory consumption. Views consume considerable amount of memory, even when they are not currently visible. Views are usually very easy to reconstruct - simply by calling the code that constructed them in the first place. That's especially very easy if you are using Interface Builder. So these views are best candidates to be freed to gain more memory.
When system doesn't have enough memory it starts calling didReceiveMemoryWarning method of view controllers which are not currently visible. If you have created your controllers from template in Xcode, this method simply calls super's (UIViewControllers's) implementation [super didReceiveMemoryWarning]. That default implementation will release self.view, which in turn should deallocate it together with all its subviews.
Now let's say that your view-controller needs access to some of the subviews to manipulate it in some way. For example you can have a UILabel element there and you want to change its content accordingly. To access this element you create a member variable (IBOutlet) and connect it to the element. Now your view-controller owns that label, so its retain-count is increased. When controller's view is released, so is the label, but because your view-controller still retains the label, it will not be deallocated. Therefore you should release the label in viewDidUnload method.
I've seen applications that were creating views programmatically (in loadView method), but loading was done in such dirty way that it was not possible to reconstruct the view after it was once deallocated. Therefore each time system was out of memory, it had called didReceiveMemoryWarning which in turn deallocated the view, but after navigating back to that view-controller application had crashed. A fast "bugfix" was to remove calling [super didReceiveMemoryWarning] in view-controllers. Well, system didn't get the memory and some strange effects occurred, but at least the application didn't crash immediately.
Now the third one - dealloc. This is called when object is not owned by anyone and its memory is going to be freed. Here you need to release all objects that you have retained. For view-controllers those are usually references to model classes.
I want to describe one more possible scenario. Let's say you have a view-controller displaying a chat with another person. Let's say it's very fancy chat, with emoticons and buddy-icons being animated. Let's say that each chat-entry is displayed as a cell of UITableView.
When your buddy sends you a message, you want to append a new cell into table-view by reloading it. Therefore your view-controller has an outlet to the table-view.
In viewWillDisappear you should stop the animations of emoticons and icons.
In viewDidUnload you should release the table-view.
In dealloc you want to release chat's history (probably NSArray of all messages sent and received during this conversation).
Now if you navigate away from your chat, viewWillDisappear gets called and you stop the animations.
When system is low on memory, and your view-controller is not visible, didReceiveMemoryWarning gets called and the view is released. Your viewDidUnload gets called and you release UITableView so that it can be really deallocated.
When you navigate back to the chat, loadView gets called again and your view is constructed again, viewDidLoad is called after that. Your model (representation of chat conversation) is still there, so the table-view's datasource has all the data as before, so table-view will display exactly the same thing as before the view was deallocated. After all viewWill/DidAppear is called where you start the animations.
When you finish chatting with your friend, you release the view controller, and it gets deallocated - dealloc is called, you release an array containing the chat messages, and cleanup everything else.
I hope it make things a little clearer.
Well that depends.
If you need to reduce the memory footprint of your app, unloading stuff while the view is not visible via viewWillDisappear is a good way to go. However you'll need to re-initalize everything once the view will be shown again, depending on its content this may produce considerable overhead - maybe even without the need.
For a small app (in terms of memory usage), using dealloc to unload your stuff is fine. It will be called only if the objects retain count drops to zero and is the last method that will be run before the object is destroyed. When using autorelease, that may not be the case right away and of course the object could be retained by some object other than the parentviewcontroller, preventing it from being destroyed and thus dealloc from being called.
You might want to check out the Memory Management Programming Guide, it'll explain things more detailed.