Iphone: Where allocate memory for dataSource? - iphone

i have an array used to populate the UITableView.
The question is where i should to allocate memory for it. I have two options in viewDidLoad or viewWillAppear, but i don't know where is more efficient from the point of view of memory management.
Thanks
Edit:
I create the view doing the following:
NextViewController *nextController = [[ReservationsViewController alloc] initWithNibName:#"NextViewController" bundle:nil];
nextController.managedObjectContext = self.managedObjectContext;
[self.navigationController pushViewController:nextController animated:YES];
[nextController release];
But i don't want to allocate memory every time is shown, only the first time the view is loaded in order to be right from the point of view of memory-management.

If you only want it to be allocated once then you should alloc it either in the init method or in awakeFromNib depending on how your view controller is created.
viewWillAppear will likely be called multiple times and viewDidLoad is not guaranteed to be called only once.

If the array is a property just release it in the dealloc like so:
- (void)dealloc {
[someArray release];
[super dealloc];
}
If for some reason you switch to creating a local array in the viewDidLoad or viewWillAppear method make sure you release it as soon as your done with it.

If you allocate memory in the viewDidLoad method it will be done only when the view is loaded to memory. If you do this in the viewWillAppear you will be doing this every time the view becomes visible.

Related

ARC: When to set a viewController to nil

I'm still struggling a bit with the idea of ARC. Let's suppose I have two very complex viewControllers A and B that each have a lot of pictures in them which are retained by each view. For argument's sake, let's suppose the first ViewController (A) retains images which take up 75 MB in RAM. The other one (B) takes up 75 MB as well.
In my App Delegate I set up my NavigationController like so:
ViewControllerA *vcA = [[ViewControllerA alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:vcA];
[navController.navigationBar setHidden:YES];
[[self window] setRootViewController:navController];
When I switch from A to B, I do it like so in ViewControllerA.m:
ViewControllerB *vcB = [[ViewControllerB alloc] init];
[[self navigationController] pushViewController:vcB animated:YES];
When I switch back, I do it like so in ViewControllerB.m:
[[self navigationController] popToRootViewControllerAnimated:YES];
Now my big question is if I still have ViewController A in my memory when I'm in ViewController B? In this case, when does the compiler release a ViewController? Could I or should I release (i.e. set it to nil) one ViewController when it is not in use?
I'm sorry if the answer is clear or if I'm totally missing the point. So any answers and explanations would be highly appreciated.
Yes, you still have ViewControllerA (you can see this with Instruments next time). That has nothing to do with ARC, it's the same without it. Let me explain:
You create a UINavigationController and put UIViewController A as the root, A is retained (in ARC it's a strong property or something like that), as you can see UINavigationController needs it right?
Now you push UIViewController B, B and A exist on memory, you UINavigationController still needs UIViewController A, it's just not showing and the view can be unloaded, if the system needs memory, but it won't release A. When you pop UIViewController B, it is released, and if there aren't references for it (again, I assume this is how ARC works) it is dealloced.
Now your question is, when is the rootViewController dealloced? Well, UINavigationController always has a root! So, while you have a UINavigationController you have a rootViewController.
Let me know in the comments if you need further explaining.
I can't help you with ARC, cause I never used it (and I don't know if I really want).
But I can tell you one thing :
When you push your ViewControllers, they all are in the navigation stack. And untill they are in the stack, they remain in memory.
Without using ARC, if I autorelease eatch viewController I push, it will be released exactly when I would pop it from the stack.
If someone know more about ARC (and when it release allocated object) I would be glad to have more info.
Thanks
Your view controller A will be retained by navController so it won't be released. Even you set vcA to nil it will not be released because navController is retaining it.
The problem is that your controller retained lots resources (images) that takes lots memory. To solve this, you can allocate the resources on viewDidLoad and free them at viewDidUnload
for example
// in your view controller
- (void)viewDidLoad {
[super viewDidLoad];
self.image = // read image to memory
}
- (void)viewDidUnload {
[super viewDidUnload];
self.image = nil; // release the image to free memory
}
Then after view controller B is pushed to navController, view controller A will get notified by UIKit that it is not the displaying controller and it will unload the view if necessary in order to free memory for other class to use.

In iphone app, with 3 viewcontrollers with UInavigationcontroller, from 2nd to 3rd view, dealloc is not called

I am posting a question since there are similar problems to mine, but not exact.
I am new to iphone app development.
I have 3 view controllers like below.
1 - Mapview controller is the 1st view controller and calls the 2nd table view controller by
[self.navigationContrller pushViewController:titlesViewController];
[titlesViewController release];
2 - titlesViewController is 2nd table view controller and in the DidSelectRowAtIndexPath method, it calls the 3rd view controller.
#implementation TitlesViewController
NSMutableArray *titleArray;
NSMutableArray *bidArray;
...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
...
[self.navigationController pushViewController:detailViewController animated:YES];
[webView release];
[detailViewController release];
[titleArray release];
[bidArray release];
NSLog(#"****** titlesviewcontoller didSelectRowAtIndexPath");
}
- (void)dealloc
{
[titleArray release];
[bidArray release];
[super dealloc];
NSLog(#"****** titlesviewcontoller dealloc");
}
#end
3 - detailViewController is the 3rd view controller to show detail info.
I did the Xcode profile->instruments->Memory leak, and there is a memory leak without
[titleArray release];
[bidArray release];
in the didSelectRowAtIndexPath in the 2nd table view controller.
I also noticed that with this app running in the IOS simulator, if I go to 3rd detail view from 2nd table view, the dealloc() method is not called, so there is memory leak without the 2 release codes for titleArray and bidArray. But if I go from the 2nd table view to the 1st view by pressing the Back button on the UINavitagation controller, the dealloc() is called. And so, no memory leak.
My question is do I really need the 2 release codes
[titleArray release];
[bidArray release];
in the didSelectRowAtIndexPath in the 2nd table view controller.
Is my observation correct?
I thought the dealloc() is invoked every time.
Thank you very much in advance.
You need to release ANYTHING you alloc. Nothing more. Nothing less. By explicit release, or by setting autorelease when allocating. If you don't alloc, you don't need to release : It's just a memory reference referencing nothing.
Why don't you put your global vars as member vars ? You should, that would be more clear. If it's not to make them available to other classes, well... Objective-C is not designed to do this. And anyway, using global vars is not recommended.

Memory Management on Views in Use

I'm just learning how to code for the iPhone using Objective-C, and I don't quite understand why a view controller needs to be released when its in use?
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:nil];
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
Thanks in advance
The navigation controller retained the detail view controller already, therefore, the retain count is 2 at that point. The release will make the retain count 1.
The dl;dr of what I have below is this: take care of your local memory management, don't worry about needing to manage the memory of API classes. They manage their own memory.
Some things to remember with Objective-C memory management:
The cocoa touch classes are responsible for retaining things you give it. Add a subview to a view? The view retains it on its own. Pushing a view controller onto a navigation controller? The navigation controller retains the view controller until it is popped off the stack.
Conversely, each time you call alloc, copy, new and/or retain there must be a corresponding release or autorelease. In the code above, you called alloc to make your view controller, giving it a retain count of 1 that you are responsible for releasing at some point.
If you use properties that are objects with dot notation and the property is a copy or retain property (usually what you want), don't do this:
self.property = [[WhateverObject alloc] init];
instead, do this:
self.property = [[[WhateverObject alloc] init] autorelease;

When is viewDidLoad called?

Is it safe to assume that an attribute, namely fetchedResultsController, of chatViewController, an instance of a subclass of UITableViewController, is always nil when viewDidLoad is called, assuming that it's set to nil in viewDidUnload? Phew!
If that's the case, then I see no immediate need to redefine the accessor function like in the Xcode example application CoreDataBooks. I'd rather just put all that code in viewDidLoad instead of in a separate function because that's the only place I'll use it.
viewDidLoad is called after your view is loaded. Whether or not fetchedResultsController is nil or not depends on how the viewController is initialized. For example, when creating the detailViewController, you could set its fetchedViewController before viewDidLoad is called:
RecipeDetailViewController *detailViewController = [[RecipeDetailViewController alloc] initWithStyle:UITableViewStyleGrouped];
detailViewController.fetchedResultsController = fetchedResultsController;
[self.navigationController pushViewController:detailViewController animated:animated];
[detailViewController release];
That said, then nil'ing fetchedResultsController in viewDidUnload would ensure that it's nil.
ViewDidLoad Called in These Secnarion:-
1.when we push the view controller after creating it’s object by segue or by stoary board id.
2.it called more than one in the case of creating instance more time in application and push it again and again.for example:-if you implement like coaursal(that having required to additional controller during scrolling) like that it’s need so it can called multiple times viewDidLoad.
3.it called when all memory instance (uiviewcontroller and it’s subclass instantiated) that means when our view is ready to load in memory with the address.
4.Remember only child class controller object is created..parent class object never been instantiated during normal Secnarion.
You have to assume that viewDidLoad can be called multiple times. If there is a memory warning sent, your view controller will unload the view from memory, and the next time it is needed viewDidLoad will be called.
viewDidLoad is called only when view is instantiated for first time . If you're not recreating the view controller each time in your application, you'll only get it called once (and called again if you get a memory warning, and the view is nil'd out).

remove ViewController from memory

I hope to load an ViewController and do something then unload (viewDidUnload) it from memory.
if (self.vViewController5.view.superview==nil)
{
ViewController5 *blueController =
[[ViewController5 alloc] initWithNibName:#"View5" bundle:nil];
self.vViewController5 = blueController;
[self.vViewController5 setDelegate:self];
[blueController release];
}
[self presentModalViewController:vViewController5 animated:YES];
later, call
[self dismissModalViewControllerAnimated:YES];
but I found that dismissModalViewControllerAnimated does not trigger the event viewDidUnload of Viewcontroller5.
I try function release but it caused program collapse.
I also try removeFromSuperView but it does not trigger the event ViewDidUnload neither.
Welcome any comment
Thanks
interdev
viewDidUnload is only called when your application receives a memory warning, and the view is not active. It's generally used for releasing retained views (including IBOutlets). You can use viewWillDisappear or viewDidDisappear to respond to a dismissal (dealloc will also be called eventually, but not necessarily exactly when the view is dismissed).
A dismissed UIViewController will not trigger the viewDidUnload, as you have discovered. However it will trigger viewWillDisappear method, if that suit your needs.