I am working on a Tab Bar based application
I have a class A with its .xib and a class B with its .xib
On class A i am loading multiple instances of class B.
i.e In class A ,i am doing.
in .m file
-(void)renderData:(NSArray *)Data
{
for(int i=0;i<[Data count];i++)
{
B *grid=[[B alloc]initWithNibName:#"Beta" bundle:[NSBundle mainBundle]];
.
.
. //do something with the grid object i.e assign new image etc..)
[self.myGrid addObject:grid]; //i have a NSMutableArray myGrid declared in .h
[grid release];
}
}
now in the myGrid Array i have all the objects of the grid saved.
Now i am adding them to the class Aplha view.
for(int i=0;i<[myGrid count];i++)
{
B *grid1=[[myGrid objectAtIndex:i]retain]; //i have done this retain because when i try to come back to this tab or try to call the same function it crashes by saying message send to deallocated instance.
[self.view addSubview:grid1.view];
}
now my problem is that how to release the grid1 object that i have retained.
You are approaching this wrong. The problem here isn't how to release the grid1 object, it's why you are retaining them in the first place. You most likely shouldn't be; you need to investigate the original crash more thoroughly.
If your grid1 objects are stored in self.myGrid then they are retained by that array. Are you releasing myGrid anywhere? As long as that is retained, your grid1 objects should be.
In addition, there are some conceptual issues here. Loading a view controller from a nib and adding it's view as a sub-view of another view controller's view is generally not correct. It's hard to recommend the correct approach without knowing exactly what you are trying to achieve though.
You do not need to pass in [NSBundle mainBundle] to initWithNibName:bundle: - you can simply pass in nil as the default behaviour is to use the main bundle.
Your comment says you have "assigned" an NSMutableArray in your header. You don't assign anything in your header, you just declare things. Have you actually initialised the NSMutableArray somewhere in your implementation?
You own any object you create when
You create an object using a method whose name begins with “alloc”,
“new”, “copy”, or “mutableCopy” (for example, alloc, newObject, or
mutableCopy).
When you no longer need it, you must relinquish ownership of an
object you own
You relinquish ownership of an object by sending it a release message
or an autorelease message. In Cocoa terminology, relinquishing
ownership of an object is therefore typically referred to as
“releasing” an object.
To release grid1 use [grid1 release];
Note: There is no reason to retain/release your grid1 object in cycle. Just
B *grid1 = (B*)[myGrid objectAtIndex:i];
[self.view addSubview:grid1.view];
I don't know what happened with your rest code but it looks like you have some memory leaks in another place.
Related
I will try and explain this as best as possible if I have this code here
ViewTwoController *home = [[ViewTwoController alloc] initWithNibName:#"contentscreen" bundle:nil];
[self presentModalViewController:home animated:YES];
[home release];
I will start a new .m and .h class. What I would like to try and do however is when this is called, have the .m and .h class where it was called from running in the background so I do not lose data.
The best example I can think of is with Android. If you begin a new class, and don't add the finish() statement in the class the call was made from, the previous class runs behind the current class (that was pushed to the front) and maintains all the data it originally had, so if you hit a return button, you will see the information you had moments ago. Is this possible? I can try add more detail if people cannot understand what I am trying to do.
You need to understand a objects life cycle a little better.
An object is brought into existence generally with a 2 part process.
allocation - (grabbing the memory for the object and its members)
initialization - (setting the object up for use)
This can be combined into single step with the +new class method which combines alloc and init.
lets introduce an example class called MyClass and an object of that class called myObject. By convention classes start with uppercase letters and objects start with lowercase letters. So Without further ado, some code:
MyClass * myObject;
this this makes an object pointer, but doesn't allocate any memory for it or direct the pointer to reference anything.
myObject = [[MyClass alloc] init];
this actually creates an instance of MyClass, passes the -init message to it, then assigns the return value of the init message to myObject. At this point the reference count of this object is 1.
myObject can potentially go out of scope but that alone doesn't free the memory that was allocated during the alloc step.
in order to free that memory a release message will need to be passed to the object.
[myObject release];
The effect of release is to decrement the reference count, if the reference count is already 1 then the object will then be passed the -dealloc indicating that it is actually being freed.
back to your question... essentially [self presentModalViewController:home animated:YES]; ends up calling -retain on home, so that it will not be destroyed until you dismiss the modal view controller. In affect when you call release or autorelease you aren't dealloc'ing the object, just telling the object:
"Hey, I don't need you anymore, and if no one else does either then free up all the memory that you grabbed earlier".
Your problem has nothing to do with "class running in the background" but more with how you manage your data.
When you present a modal view controller, its parent (the view controller you presented it from) isn't destroyed (unless you specifically release it, which would probably crash your app later). So if you're wondering whether its still in memory; it is. As for tasks still running, it depends on what those tasks are. For example, you can still send it messages (call methods) and it will gladly receive those messages from your or from a delegate and perform whatever action it has to while it's off-screen.
Hope that helped.
In this case you are presenting new view controller. The main thread will be in the new controller presented. If you want something to run in background in the previous view controller then you can create a background thread. This can be done using [self perfomselectorInThebackground ... ] Or some other methods like GCD. (The main thing is you should not block Main thread)
There are a few concepts about iPhone memory management that have got me confused, so I was hoping that someone could clarify these.
(a) Say that I am calling a function which returns an image, and I want to store that returned image in a variable so that I can assign it to various other variables without having to re-call the image generation function each time. At the moment I am doing the following:
UIImage *storedImage = [someFunction returnImage];
and because the storedImage is not alloc'ed I am not releasing the variable.
However, should I be explicitly alloc'ing and releasing the UIImage instead?
UIImage *storedImage = [[UIImage alloc] init];
storedImage = [someFunction returnImage];
...do stuff...
[storedImage release];
What is the implication of doing the direct assignment without alloc rather than alloc'ing the variable and then assigning?
(b) In the init method for various classes I am setting up the instance variables. At the moment I am doing the following:
self.arrayVariable = [[NSMutableArray alloc] init];
However, I have seen others do the assignment this way:
theArrayVariable = [[NSMutableArray alloc] init];
self.arrayVariable = theArrayVariable;
[theArrayVariable release];
or
theArrayVariable = [[NSMutableArray alloc] init];
arrayVariable = theArrayVariable;
[theArrayVariable release];
...which is the same as above, but without the self.
What is the difference between the three methods and which is better to use?
Regarding returning objects from methods, you should always return an autoreleased object from any method which does not begin with the name alloc, new, or contains copy. This is defined in Apple's object ownership policy, which states that you own any object that you create ("create" is defined as an object which you sent retain to, or used any of the aforementioned messages to retrieve an object), and that you are responsible for relinquishing ownership of that object by sending it the release or autorelease message.
The first method using self uses the property setter to set the instance variable to the argument (in this case whatever is on the RHS of the assignment).
This will do whatever you specified in your #property declaration (for example if you specified retain, the setter will retain the new value and release the old value).
The second method sets up a pointer to an NSMutableArray and passes it off to your property setter via self, which will most likely retain it, thereby bringing the reference count up to 2, since the object was previously alloc-ed, so you need to release it after this line to bring it back down to 1.
The third method will not work, because you are releasing an object with a reference count of 1 at the point of invoking release. How so you ask? Well, the first line sets up a pointer to an alloc-ed object, then directly assigns it to your instance variable, which will just point the ivar to the same object that theArrayVariable is pointing to. Then, that same object that theArrayVariable is pointing to gets sent the release method, which will effectively bring down the reference count of your ivar as well as the receiver, to 0. At this point both your instance variable and theArrayVariable will get deallocated.
a) The general rule for objective-c is that if you alloc it you must release it. In the first example, the method is returning a pointer to an object that already exists, and therefore you are not responsible for releasing it. In the second example, the first like is pointless since you aren't using allocated memory for stored image. This may cause a memory leak.
b) The first two are just stylistic differences, with no difference in outcome. In those, you will be left with arrayVariable pointing to the object returned by [[NSMutableArray alloc] init]; (assuming you have retain in the #property declaration) and you should release it in the -dealloc method. As stated above, the third will not work because you are merely passing off the pointer.
Here is a useful article for understanding obj-c memory management: http://memo.tv/memory_management_with_objective_c_cocoa_iphone
a) The code you gave does not do what you want. When you say
UIImage *storedImage = [someFunction returnImage];
someFunction returns an image object to you, but it does not guarantee that the image object will live forever. If you do not want the image to be freed without your permission in a future time, you should own it by calling retain like this:
UIImage *storedImage = [[someFunction returnImage] retain];
So now, this image object is owned by both someFunction and you. When you finish your work with this object you release it by calling release. When both someFunction and you call release for this object, it will be released (Of course if it is not owned by another owner).
In the other code segment, you create an image object and own it by calling
UIImage *storedImage = [[UIImage alloc] init];
But then you lose its reference by assigning a new object to the storedImage pointer by calling someFunction. In this situation the image created by you is not freed but continues to live somewhere in the memory.
I've subclassed some UITextField and added some custom properties.
In a UITableViewController, in the ViewDiDLoad I init them, and in the cellForRowAtIndexPath I add them to the cell with [cell.contentView addSubview:customTextField];
Each cell has a different customTextField as all of them are very different.
Where I should call the [customTextField release] ?
After I add them to the cell view ?
If for example I call [self.tableView reloadData] my customTextField are going to be added again to the cell, so maybe I should change my approach in doing this ?
thanks for the orientation ...
regards,
r.
You release an object when you no longer have any interest in it. This happens for many reasons; it might be because you've finished with the object, or have passed the control over the object lifetime to another object. It might be because you're about to replace the object with a fresh instance, it might be because you (the owner object) are about to die.
The last one seems to be relevant in your case. You create these object in viewDidLoad and repeatedly need them (i.e. to add them to cells) until your object is no longer functioning. In this case, just as you create them in viewDidLoad, you can release them in viewDidUnload.
Edit: I should really mention autorelease, but this isn't relevant in this instance. Memory management is best handled with a notion of 'owner' - the person who creates something (or retains it) should be responsible for deleting it (or releaseing in ObjC parlance). autorelease handle some cases where you need to give an object to an alternate owner, having previously owned it yourself (typically via a method return). If you are the creator, you can't just release it before returning it to the new owner, as it will be deleted before the new owner has a chance to stake an interest in it. However, you can't just not release it; it will leak. As such, the system provides a big list of objects that it will release on your behalf at some point in the future. You pass your release responsibility to this list, then return the object to the new owner. This list (the autorelease pool) ensures your release will occur at some point, but gives the new owner a chance to claim the object as theirs before it's released.
In your case, you have a clear interest in owning the objects for the lifetime of your view controller - you need to, at any time, be able to add them to view cells in response to a table data reload. You're only done with them when your view controller dies, so the viewDidUnload (or possibly dealloc) is the only sensible place to release them.
I always release my controls directly after I added them to a view using addSubView. When I work with tables, I also initialize them in the cellForRowAtIndexPath method.
Therefor the object stays alive the shortest time.
Adam Wright explains the theory of this very well, but let me give you some practice. You're thinking about this problem far too hard, and that almost always leads to bugs. There is a simple solution that solves this problem almost every time: Retain all ivars using accessors; don't retain non-ivars.
.h
#interface ... {
UITextField *_customTextField;
}
.m
#property (nonatomic, readwrite, retain) UITextField *customTextField;
...
#synthesize customTextField=_customTextField;
-(void)viewDiDLoad {
self.customTextField = [[[UITextField alloc] init....] autorelease];
}
...
- (void)dealloc {
// I do not recommend accessors in dealloc; but everywhere else I do
[_customTextField release]; _customTextField = nil;
}
Never access your ivars directly, except in dealloc (even that is controversial and some people recommend self.customTextField = nil; in dealloc; there are arguments either way). But never assign your ivars directly. If you will follow this rule, you will find that most of your memory problems go away.
The safest way to handle object ownership is to autorelease the view directly after initialization:
FooTextField* textField = [[[FooTextField alloc] init] autorelease];
[myCell.contentView addSubview:textField];
Adding the text field to a superview (the UITableViewCell's contentView) retains it. This way you don't have to care about releasing the view afterwards.
There seems to be a resentment against autorelease in the iPhone developer community. In my opinion, this resentment is unfounded. Autoreleasing an object adds very little overhead to the program if the objects lives longer than the current pass through the run loop.
Every object in Obj-C has a reference counter (retainCount), and when this counter goes to 0 the object is deallocated. When you allocate and initialize an object, the reference count is set to 1 - but you can retain it as many times you want to.
UITextField *textField = [[UITextField alloc] init]; // Reference counter = 1
[textField retain]; // Reference counter = 2
[textField retain]; // Reference counter = 3
The opposite of retain is release, which subtracts from the reference counter;
...
[textField release]; // Reference counter = 2
[textField release]; // Reference counter = 1
You can always get the reference counter of your objects;
printf("Retain count: %i", [textField retainCount]);
The method addSubview of UIView does retain your passed in sub view - and when it's done with it it releases it. If you need your UITextField later, in another scope (when the UIView is done with it and has released it) - you should not release it after you've added it to the super view. Most of the time you actually don't need to hold on to a reference, so you should release it after you've added it to the super view. If you dont - you can release it in the dealloc method of your scope.
Take a look at UITableView -dequeueReusableCellWithIdentifier: and -initWithStyle:reuseIdentifier:.
In -tableView:cellForRowAtIndexPath:, use -dequeueReusableCellWithIdentifier: and check if the result is nil. If it is, instantiate a new cell with -initWithStyle:reuseIdentifier:.
Send -autorelease to your customTextField upon creation and adding to the respective cell.
You should not add subview in cellForRowAtIndexPath! This will slow down the view as you add a subview each time the cell is displayed. Try using custom UITableViewCell class for that purpose.
Here is a perfect solution of UITableView customization
http://cocoawithlove.com/2009/04/easy-custom-uitableview-drawing.html
works jut perfectly
Say I have a tableview class that lists 100 Foo objects. It has:
#property (nonatomic, retain) NSMutableArray* fooList;
and I fill it up with Foos like:
self.fooList = [NSMutableArray array];
while (something) {
Foo* foo = [[Foo alloc] init];
[fooList addObject:foo];
[foo release];
}
First question: because the NSMutableArray is marked as retain, that means all the objects inside it are retained too? Am I correctly adding the foo and releasing the local copy after it's been added to the array? Or am I missing a retain call?
Then if the user selects one specific row in the table and I want to display a detail Foo view I call:
FooView* localView = [[FooView alloc] initWithFoo:[self.fooList objectAtIndex:indexPath.row]];
[self.navigationController pushViewController:localView animated:YES];
[localView release];
Now the FooView class has:
#property (nonatomic, retain) Foo* theFoo;
so now BOTH the array is holding on to that Foo as well as the FooView. But that seems okay right? When the user hits the back button dealloc will be called on FooView and [theFoo release] will be called. Then another back button is hit and dealloc is called on the tableview class and [fooList release] is called.
You might argue that the FooView class should have:
#property (nonatomic, assign) Foo* theFoo;
vs. retain. But sometimes the FooView class is called with a Foo that's not also in an array. So I wanted to make sure it was okay to have two objects holding on to the same other object.
To answer your main question, yes you can multiple objects retaining an instance. That is exactly the point of reference-counted memory management. Have a look at the Cocoa Memory Management Programming Guide for more info. Then re-read it. It has all of the answers and will be your best friend.
Basically, sending a -retain message indicates that the sender "owns" the receiver in the sense that the receiver should not be deallocated until all owners have released their ownership. Thus, individual instances don't need to know (nor should they care) whether other owners exist. Retain anything you need to keep around and release it when you're done with it. When all owners have released their ownership, an intsance can be deallocated.
On a side note,
#property (retain,readwrite) NSMutableArray *myArray;
declares that the class declaring this property will retain the NSMutableArray instance. NSArray, NSDictionary, and NSSet (and their mutable subclasses) always retain their contents.
As others say, what you are doing is correct, and the code looks correct to me. I have tens of references to the same object in my code and as long as I have balanced all the retains and releases, everything works fine.
To add a bit more detail... you ask:
because the NSMutableArray is marked as retain, that means all the objects inside it are retained too?
These are two different things. All collection classes (Dictionaries, Arrays, Sets) automatically retain things that you add to them, and release their content objects when the collection object is deallocated. (In case of NSMutableArray, the content object gets released either if you remove it individually from array, or when you deallocate the whole array.)
This has nothing to do with whether the collection object itself is retained or assigned as a property. The only thing to consider there is that if your policy for the collection object property is not correct, it might get released sooner or later than you think and things may get out of balance.
As others say... read the memory management guide, and practice. :) Oh, and read other people's code too from this perspective and try to understand how/why they are doing their memory management.
One other small thing... for every retained property, make sure you have a release call in the object's dealloc method.
Yes, it's ok. That's the entire point of a reference counting memory management system.
So I modified Apple's PageControl example to dynamically load various navigation controllers (along with their root view controllers) into the scroll view. I also added a technique that attempts to unload a navigation controller when it's no longer needed. I've only been at ObjC for a little over a month, so I'm not sure if I'm doing the unloading correctly. Please see my code below, followed by my questions.
First I create a mutable array and fill it with nulls, just like Apple does:
// Create dummy array for viewControllers array, fill it with nulls, and assign to viewControllers
NSMutableArray *array = [[NSMutableArray alloc] init];
for (unsigned i = 0; i <= kNumberOfPages; i++)
{
[array addObject:[NSNull null]];
}
self.viewControllers = array;
[array release];
...Later, I fill the array with UINavigationController objects like so (this is just partial code, please excuse the missing parts...the main idea is that I alloc a couple of things, assign them and then release):
id controller = [[classForViewController alloc] initWithNibName:NSStringFromClass(classForViewController) bundle:nil];
navController = [[UINavigationController alloc] initWithRootViewController:controller];
[controller release];
[self.viewControllers replaceObjectAtIndex:page withObject:navController];
[navController release];
...Finally, if a page doesn't need to be loaded anymore I do this:
[self.viewControllers replaceObjectAtIndex:i withObject:[NSNull null]];
Questions:
My understanding is that once I replace the navigation controller in my viewControllers array with null, the array releases the navigation controller. Thus the navigation controller's retain count hits zero and it no longer takes up memory. Is this correct?
What about the root view controller inside the navigation controller? Do I need to do anything with it or does it get released automatically once the navigation controller's retain count hit zero?
Thanks!
Yes. Any object put into a collection is sent a retain message. Likewise any object removed from a collection is sent a release message, the cause of the removal is irrelevant.
Yes, all objects will release all the objects it owns when they are released.
This all boils down to the simple principle of ownership that Cocoa defines:
You own the object if you received it as return value by calling a method that:
Is named alloc or new.
Contains the word copy, such as copy and mutableCopy.
You own the object if you call retain.
You may only call release and autorelease on objects you own.
You must release all owned objects in your dealloc methods.
There is just one exception; delegates are never owned. This is to avoid circular references and the memory leaks they cause.
As a side effect this also means that when you yourself are implementing a method, you must return an auto released object unless you are implementing new, or a method with copy in it's name. Objects returned as out arguments are always autoreleased.
Follow this strictly and Objective-C can be treated as if it is garbage collected 95% of the time.
Presumably yes, once your retain count reaches zero (however or whenever that happens) your object will receive the dealloc message. You can put a breakpoint to ensure that is happening. Instruments comes with a Leaks utility that should help you find memory problems, it's a great tool and I suggest using it frequently.
I'm not quite sure what you mean by "do anything to it". I presume you mean release it. The general pattern is that if you alloc or retain, you release. You can roughly guess if there is going to be a problem if your allocs and retains outnumber your releases (or vice versa, you don't want to double release).