I'm trying to understand memory management on iOS. I created this interface:
#interface Player : NSObject {
PlayerType pType;
PlayerWeapon pWeapon;
}
#property(nonatomic, readwrite, retain) pType;
#property(nonatomic, readwrite, retain) pWeapon;
#end
and this in the implementation file:
#synthesize pType;
#synthesize pWeapon;
In the header file, I use the retain property because pType and pWeapon are not standard C structs. From what I understand, if they were C structs, I would use assign instead. Since I've used retain, does that mean this class retains the object or whichever class instantiates it? For example, if I do this in another class:
Player *player = [[Player alloc] init];
Does this new class have to call [player release] or will the object automatically be released?
A good, general rule is that whatever you alloc/init or copy you have "created" and own, therefore you will have to release it. So yes, the object that owns player will need to release it when it is done using it. This applies if the Player object is created just for a local scope within a method, or if it is an ivar.
Remember though, that if you ever decide to create an autoreleased Player object, you will need to retain the object either through the property dot syntax or an actual retain message to keep the Player object from being autoreleased after the local method has finished executing.
// Retaining an autoreleased object
self.player=[Player playerWithName: #"George"];
or
player=[[Player playerWithName: #"George"] retain];
Good luck
When you make a property "retained" the compiler generated setter method takes responsibility of making sure objects are release and retained correctly. This property essentially handles the work of releasing the previous object it was referencing and retains (takes ownership) of the object that was assigned. You will also need to add the following code in the implementation file to release these objects when the Player object is released:
- (void) dealloc
{
[pType release];
[pWeapon release];
[super dealloc];
}
This means that even though the internal properties are "retained," when a "Player" object is allocated, you will still have to release it at some point.
The caller of [[Player alloc] init] is responsible for sending the new Player object a release message. The Player object's properties don't affect that responsibility.
Related
I have a singleton object obj1, having a NSMutableArray member called Objects
and i added a category called NSObject (Register)
#implementation NSObject (Register)
-(id)init
{
[[obj1 defaultObject] addObjectToView:self];
return self;
}
#end
the addObjectToView method just simply add the object to the array
-(void)addObjectToView:(id)object
{
[object retain];
[Objects addObject:object];
}
(Object is a NSMutableArray)
the problem is, when i tried to test it, i did
NSWindow *window = [[NSWindow alloc] init];
and then i got 505 scary objects in the array,
did i do anything wrong?
BTW, it is possible to manage the relationship of all objects and send isolate objects dealloc message to implement a garbage collector in Objective-C ?
Don't do that!
This catches almost all objects created and prevents them from ever being deallocated. Actually even twice as you retain them manually and then add them to the mutable array which retains them as well.
Also you cannot override methods in categories. It sortof does work, but as soon as there is a second category that overrides the same method it's undefined which one will actually be used.
Implementing a garbage collector on top of that is not going to work either. Also you don't want a garbage collector. Apple used to provide one, but it is deprecated now and will be removed. Also you don't need it - use ARC.
Assuming, the following declaration for class A
#property(nonatomic, assign) DoublyLinkedList *doublyLinkedList;
, that as part of init, initialized the object
- (id)init {
self = [super init];
if (self) {
doublyLinkedList = [[DoublyLinkedList alloc] init];
}
return self;
}
and that a method
- (DoublyLinkedList*) doSomethingAndReturn {
that ultimately
return doublyLinkedList;
Does class A owns the doublyLinkedList after the return?
EDIT: init added with alloc
You are not calling retain on it, but in init you are calling alloc on it, so it does have a retain count of 1 -- you own it and you should release it in dealloc.
You could simply alloc it and release it in dealloc. The caller of the property can choose whether to retain. Another option would be to create the object in init, autorelease it and then assign it to the property with (retain) instead of (assign). That way, if other places in the code alloc and assign to that property, the object you alloc'd will get released. Then in dealloc, what it's currently assigned to will get released.
Yet another option if you don't want others to set it would be to have a (readonly) property and a _doubleLinkedList iVar and then #synthesize doublyLinkedList = _doubleLinkedList. Then you can allocate it once in init and know that no one else will assign it, and then release it in dealloc.
A good analogy is that when you retain, you're putting a leash on it. Multiple items can put a leash on that object. It is freed only when everyone has taken the leash off.
A good guide to read:
Apple's Memory Management Programming Guide
Specifically from that doc, these rules help:
You own any object you create You create an object using a method
whose name begins with “alloc”, “new”, “copy”, or “mutableCopy” (for
example, alloc, newObject, or mutableCopy).
You can take ownership of an object using retain A received object
is normally guaranteed to remain valid within the method it was
received in, and that method may also safely return the object to its
invoker. You use retain in two situations: (1) In the implementation
of an accessor method or an init method, to take ownership of an
object you want to store as a property value; and (2) To prevent an
object from being invalidated as a side-effect of some other operation
(as explained in “Avoid Causing Deallocation of Objects You’re
Using”).
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.
You must not relinquish ownership of an object you do not own This
is just corollary of the previous policy rules, stated explicitly.
Objects aren't really "owned" in that way. Objective-C will free up the memory for an object when its retain count gets to 0. If class A depends on doubleLinkedList being "kept alive" as long as an instance of class A is alive, then object A retains doublyLinkedList to increase that retain count by 1. When object A returns a reference to doublyLinkedList as you have above, then the caller who receives that result may elect to retain the object as well, which would increase the retain count by one again.
So try not to think of it as owning an object. Instead, think of it as expressing an interest in the existence of an object. As long as someone continues to be interested in that object, as expressed by its retain count, then the object will not be deallocated.
As you've defined it, class A has not ever retained doublyLinkedList. So no, it has no stake in it. In fact because doublyLinkedList is not retained by class A, it could be deallocated at any time during execution and cause an EXEC_BAD_ACCESS crash.
There are two obvious ways to deal with this.
Class A should retain doublyLinkedList while it's using it, and autorelease it before it returns it.
Another 'parent' object can retaining both doublyLinkedList and the instance of class A, and it's up to that 'parent' object to make sure doublyLinkedList doesn't get deallocated while the class A object is using it.
Edit:
If you alloc-init the object when you initialize Class A, as you've added above, then you should only release the object when Class A is deallocated. This makes for a simple object life-cycle. An instance of Class A is created, it creates a DLL object. That object persists until the Class A instance is destroyed. If other objects want to use the DLL, they simply request it from the class A instance, and retain it.
The goal with retain release is to code in such a way that you can be sure you have an EVEN number of retain calls, and release calls on an object. For every:
- (id)init {
self = [super init];
if (self) {
doublyLinkedList = [[DoublyLinkedList alloc] init];
}
return self;
}
You need a:
-(void)dealloc {
[super dealloc];
[doublyLinkedList release]
}
If your class a object is going to be creating and processing more than one DLL object, then don't create it in -(id)init and use retain for the property declaration.
then:
ClassA *newClassAObject = [[ClassA alloc] init]; // create class a object
newClassAObject.doublyLinkedList = [[[DoublyLinkedList alloc] init] autorelease]; // make a DLL object, only retained by class a object.
DoublyLinkedList *dll = [newClassAObject doSomethingAndReturn]; // process the list somehow
[dll retain] // we own this now
newClassAObject.doublyLinkedList = nil; // class A object gives up interest in dll.
newClassAObject.doublyLinkedList = [[[DoublyLinkedList alloc] init] autorelease]; // now process another one.
... and on and on ...
I've done all sorts of research today on best practices with regards to declaring IBOutlets and instance variables, managing them, using the correct accessors and properly releasing them. I'm pretty much there, but I've got some niche questions that I hope somebody will be able to advise the best practice on. I'll format them as code and comment the questions so as to make it easier to understand. I've excluded some obvious parts that I didn't think were relevant and can be safely assumed to work (like pre-processor stuff, #end, required implementation methods etc).
MyViewController.h
#class OtherViewController;
#interface MyViewController : UIViewController {
NSString *_myString;
BOOL _myBOOL;
}
// The first two properties aren't declared in the interface
// above as per best practices when compiling with LLVM 2.0
#property (nonatomic, retain) OtherViewController *otherViewController;
#property (nonatomic, retain) UIButton *myButton;
#property (nonatomic, copy) NSString *myString;
#property (readwrite) BOOL myBOOL;
MyViewController.m
#implementation MyViewController
// Synthesizing IBOutlets on iOS will cause them to be
// retained when they are created by the nib
#synthesize otherViewController;
#synthesize myButton;
// Assign instance variables so as to force compiler
// warnings when not using self.variable
#synthesize myString = _myString;
#synthesize myBOOL = _myBOOL;
- (void)viewDidLoad {
// QUESTIONS:
// 1. Ignoring convenience methods, can you still alloc and init in dot notation
// even when it's being properly synthesized?
self.myString = [[NSString alloc] initWithString:#"myString"];
self.myString = existingNSStringObject;
// 2. Should you always call methods for IBOutlets and instance variables using dot notation?
// Is there any difference seeing as these aren't directly invoking setters/getters?
[self.myButton setText:self.myString];
[myButton setText:self.myString];
[self.otherViewController.view addSubview:mySubview];
[otherViewController.view addSubview:mySubview];
[self.myButton setAlpha:0.1f];
[myButton setAlpha:0.1f];
self.myButton.alpha = 0.1f;
myButton.alpha = 0.1f;
// 3. How fussy are scalar variables in terms of getters and setters,
// given that there is a #synthesize declaration for them?
self.myBOOL = YES;
myBOOL = NO;
if(self.myBOOL) { ... }
if(myBOOL) { ... }
// 4. On instantiation of new view controllers from NIBs, should you use
// dot notation? (I haven't been doing this previously).
otherViewController = [[OtherViewController alloc] initWithNibName:#"OtherView" bundle:nil];
self.otherViewController = [[OtherViewController alloc] ... ]
}
- (void)viewDidUnload {
// 5. Best practice states that you nil-value retained IBOutlets in viewDidUnload
// Should you also nil-value the other instance variables in here?
self.otherViewController = nil;
self.myButton = nil;
self.myString = nil;
}
- (void)dealloc {
[otherViewController release];
[myButton release];
[_myString release];
}
I always declare and explicitly set a property's underlying instance variable. It's a little more work up front, but in my mind it's worth it to explicitly differentiate variables and properties and see at a glance what instance variables a class has. I also prefix instance variable names, so the compiler complains if I accidentally type property instead of object.property.
Calling alloc / init creates an object with a retain count of 1. Your synthesized property will also retain the object, causing a memory leak when it's released (unless you release your property right after, but that's bad form). Better to alloc / and release the object on a separate line.
Dot notation is effectively the same as calling [self setObject:obj]. Not using dot notation accesses the underlying instance variable directly. In init and dealloc, always access the instance variable directly as the accessor methods can include extra operations (such as key value observing notifications) that are not valid when the object is being created or destroyed. All other times use the synthesized accessor methods. Even if you're not doing anything special now, you might later override these methods later to change what happens when the variable is set.
Scalars work the same way, only you don't have to worry so much about memory.
One accesses the synthesized accessor methods, the other accesses the instance variable directly. See questions one and two again, and be careful about memory leaks!
The view controller may be pushed onto the screen again, in which case your viewDidLoad method will be called a second time. If you're setting initial values in viewDidLoad, go ahead and set your properties to nil here. This makes sense for properties that use a lot of memory and aren't going to affect the state of the view. On the other hand if you want the property to persist until you're sure it's no longer needed, create it in your init method and don't release it until dealloc.
1) You've slightly misunderstood #synthesize. #synthesize does nothing with the object. It only tells the compiler to generate the getter and setter methods according to the options used in your #property declaration
// Synthesizing IBOutlets on iOS will
cause them to be
// retained when they
are created by the nib
The outlets aren't retained (outlets are just notices to interface builder and don't affect the code), the objects are retained when the setter generated by #synthesize is used. When the nib is loaded, the loading system calls your generated setter.
2) Deciding whether to use accessors in objective C is no different from deciding to use accessors in any other object oriented language. It is a choice of style, need and robustness. That the accessor is serving as an IBOutlet makes no difference.
But in objective C I would suggest you should NOT use accessors in two places: dealloc and within the var's accessor method itself.
And if you ARE using the accessors in init then you need to be careful about your retain counts.
self.myString = [[NSString alloc] initWithString:#"myString"];
This line leaks memory. Using your copy accessor retains the object, so you should release it here after creating it.
3) Not sure what you mean by fussy. Possibly see answer to 2)
4) See 2) and be careful about memory management. If you call alloc/init you are now responsible for releasing the object - this is entirely independent of the retains/releases used by accessors and dealloc.
5) No, you should not nil other instance variables in viewDidUnload. Your controller is expected to maintain its state even if the view goes away. viewDidUnload is only for cleaning up potentially memory-heavy view objects when the controller's view is not currently on screen.
Consider a navigation controller. View controller 1 is on the stack and then view controller 2 is pushed and is now visible. If memory conditions get low, the system could attempt to unload view controller 1's view and will then call viewDidUnload.
Then popping view controller 2 will not create the view controller 1 object again, but it WILL load view controller 1's view and call viewDidLoad.
Re comments
2) That's exactly right - you can use a convenience constructor or release immediately after your alloc/init and assignment, or release before the block exits, or autorelease. Which you choose is mostly a matter of style (though some would argue against autorelease - but not me!)
3) There are accessors for scalars - you have created some in your code
#property (readwrite) BOOL myBOOL;
This creates methods myBOOL and setMyBOOL on your class.
Remember that there is nothing special about dot notation. It is only a convenience and when the code is compiled myObject.property is exactly equivalent to [myObject property] and myObject.property = x is exactly equivalent to [myObject setProperty:x]. Using dot notation is purely a style choice.
Dot notation and brackets notation are pretty much the same.
By self.myVariable you are accessing the getter of the property of the instance variable myVariable and by myVariable you are accessing the local variable. They're not the same thing.
You can customize the setters and the getters by overriding the methods and specific some certain conditions for them.
See first answer ( brackets are preferred - better understanding of the code )
Better make a separate method.
Like:
- (void) releaseOutlets {
self.firstOutlet = nil;
self.mySecondOutlet = nil;
……………………
self.myLastOutlet = nil;
}
and then call this method both in viewDidUnload and in dealloc methods.
Hope it helps !
I see in some sample code that autorelease is used. I am not familiar with the instances when this is required. For example, if I create an annotation object
Header file
#interface someViewController: UIViewController
{
Annotation *annotation;
}
#property (nonatomic, retain) Annotation *annotation;
#end
Implementation file
#implementation someViewController
#synthesize annotation
#end
Question: Is it the correct approach if I initialize my annotation object in the implementation file like this?
self.annotation = [[Annotation alloc] initWithCoordinate:location];
Do I need to set autorelease for this? Or can I just do it the normal way and add the release in the dealloc method?
this is correct:
self.annotation = [[[Annotation alloc] initWithCoordinate:location] autorelease];
because annotation property is declared as a retain property, so assigning to it will increment its retain count.
you will also need, all the same, to release self.annotation in -dealloc.
in short:
init will set retain count to 1;
assigning to self.annotation, will set it to 2;
autorelease will set it back to 1 when the main loop is executed again;
release in dealloc will set the retain count to 0, so that the object will be deallocated);
the best way to think of autorelease is the following, in my opinion: autorelease will "schedule" an "automatic" release for your object at some (near) point in future (typically when the control flow goes back to the main loop, but details are hidden in the hands of Apple).
autorelease is mostly useful in conjunction with init, specifically in the following cases:
when you init a local variable, so that you don't have to release it explicitly before it goes out of scope (the main loop will do that for you);
when you return a pointer to an object you have just created without keeping ownership of it (typical case of the create/make* kind of selectors, the receiver is required to retain it to get ownership);
with properties that retain, when you assign to them an object that they should own uniquely;
with data structures that increment the retain count (NSMutableArray, NSMutableDictionary, etc): you should generally autorelease a newly inited object when you add it to such data structure.
apart from case 2, it is evident that the use of autorelease is meant to improve readability of the code and reduce the potential for errors (meaning that in all of the other cases, you could simply release explicitly your object after the assignment or at the end of the scope).
when using properties, you have always to check whether they are of the retain or assign/copy case; in the first case, assigning a newly inited object to a property generally requires autorelease.
Anyway, I would suggest at least skimming one of the many tutorial on memory management for iOS.
Autorelease is telling the object to release itself before leaving the scope.
Sometimes when you code, you'll encounter something like this
- (void)doSomething
{
if(true)
{
NSString *foo = [[NSString alloc] initWithString:#"foo"];
//Some execution here
[foo release];
}
}
- (void)doSomething
{
if(true)
{
//By doing this is telling to to release foo object before getting out of the scope
//which is similar with above practice
NSString *foo = [[[NSString alloc] initWithString:#"foo"] autorelease];
//Or you can do it this way
NSString *foo = [[NSString alloc] initWithString:#"foo"];
[foo autorelease];
//Some execution carry on, it'll release foo before entering next scope
}
//This is out of the scope
}
Of course, releasing an object doesn't mean deallocating the object.
Sometimes you retain the object so you can still use it outside of its scope.
Judging from your question, if your the object is located within your header file/interface.
You should release it in dealloc method. CMIIW.
I'm still learning about Objective-C memory management. I'm trying to implement several simple classes in an example program that I'm building.
As an example, say I have the following class definition:
#import <UIKit/UIKit.h>
#interface customViewController : UIViewController
{
customObject *myCustomObject;
}
#property (retain) customObject *myCustomObject;
- (void)replaceCustomObject:(customObject *)newObject;
#end
For the property, I use the standard synthesize keyword...
#synthesize myCustomObject;
Then please assume that in the instance of customViewController the myCustomObject is already set with a valid value and is in use. Then the method replaceCustomObject is defined as:
- (void)replaceCustomObject:(customObject *)newObject
{
//Does this cause a memory leak because I just assign over
//the existing property?
self.myCustomObject = newObject;
}
As the comment asks, does this leak memory? Or is this the valid way to replace a previous object with a new object?
Thank you,
Frank
As others have mentioned, your code is perfectly valid and won't leak memory when assigning to the property.
If you have forgotten to implement a proper dealloc method, the last object assigned will be leaked when your customViewController is destroyed. A proper dealloc implementation would look like so:
- (void)dealloc
{
self.myCustomObject = nil;
[super dealloc];
}
That's perfectly valid, and does not leak memory. The synthesized accessors manage retain counts correctly.
(As an aside, you don't need that replaceCustomObject: method; since your property is readwrite by default, you have an auto-generated setCustomObject: method that clients of your class can use, and which follows the normal Cocoa naming conventions.)
According to this, if you use (retain) in your declaration, the synthesized method will release the old value first, then retain the new one:
if (property != newValue) {
[property release];
property = [newValue retain];
}
the property accessor syntax
self.x = y;
has the same effect as calling the setter method explicitly:
[self setX:y];
The accessor method will do whatever it has been written to do. In your case, for a #property(retain) property that has been #synthesized, the accessor will release the old object and retain the new one.
So, calling the setter, whether explicitly or through the '.' syntax, will do the right thing - including the right memory management.
So in short: no, this will not leak memory.