strong, weak, and id - iphone

I did some iOS development back when iOS 3.0 came out, but for two years I lost track of how iOS was doing.
I remember that you would do retain back in iOS 3.0 and even so, I still don't remember exactly what the reason for retaining in a setter was. This is just the one thing that is stumping me so far.
And last but not least there's the idea that local variables are strong by default in iOS 5 with ARC. How can they be strong if some of them don't have setters? (As an example, id.)
Some code to explain what I mean:
+(double) popOperandOffStack:(NSMutableArray *) stack{
double result = 0;
id topOfStack = [stack lastObject];
// how is topOfStack retaining [stack lastObject] if it's simply id?
if (topOfStack) [stack removeLastObject];
if ([topOfStack isKindOfClass:[NSNumber class]]){
result = [topOfStack doubleValue];
}
else if ([topOfStack isKindOfClass:[NSString class]]){
if ([topOfStack isEqualToString:#"+"]){
result = [self popOperandOffStack:stack] + [self popOperandOffStack:stack];
}
if ([topOfStack isEqualToString:#"-"]){
result = [self popOperandOffStack:stack] - [self popOperandOffStack:stack];
}
if ([topOfStack isEqualToString:#"*"]){
result = [self popOperandOffStack:stack] * [self popOperandOffStack:stack];
}
if ([topOfStack isEqualToString:#"/"]){
result = [self popOperandOffStack:stack] / [self popOperandOffStack:stack];
}
}
return result;
}

You can send messages to objects without knowing their exact type at compile time. In fact, you routinely do that when you send messages to objects that you get back from arrays: you do not need to cast id to the exact type, you can simply send a message, and Objective C will dispatch it correctly. The only exception to this rule is accessing properties with the dot . syntax: you do need a cast there.
Every object whose class inherits from NSObject responds to retain, release, autorelease, and so on. This is all that the ARC needs to know. In the worst case you will get "an object does not respond to selector" message if an id that you have happens to point to something invalid.

You appear to be confusing properties with instance variables and local variables.
Variables do not have setters. Properties have setters. Properties of any type can have setters (except possibly void). Instance variables might happen to correspond to properties, but the variables themselves do not have "setters". obj->ivar will never call a setter, not even under ARC.
ARC simply does approximately three things:
Insert retain, release, autorelease, and dealloc for you. When you write
// ARC
{
id foo = [array lastObject];
...
}
it gets translated to approximately
// MRC
{
id foo = [[array lastObject] retain];
...
[foo release];
}
It uses Objective-C naming conventions to figure out what it needs to retain and release. There are a few optimizations (it actually uses objc_retain() and friends for reasons described in the ARC spec, plus a few more functions to handle autoreleased objects more efficiently than -autorelease.)
Release __strong ivars in -dealloc for you. It does not call the property setters; it just releases the ivars. It might also set them to nil.
Zeroing weak references.__weak variables are read/written with objc_copyWeak() and friends instead of being accessed directly. There's additionally a hook in -[NSObject release] (or so) in order to implement zeroing weak references correctly.
Additionally, the semantics surrounding blocks and __block variables are changed in a way that isn't easy to replicate via MRC. Apart from that, I believe everything ARC does can be replicated by calling the ARC runtime support function calls.
The only connection between ARC and setters is that you can get rid of a lot of properties, because the compiler inserts retain/release on ivar access.

Related

What is the use of unsafe_unretained attribute?

I know the definition of unsafe_unretained.
So i don't expect anyone to write its definition.
I want to know its use with example, and how it works with memory management.
unsafe_unretained only exists in ARC (Automatic Reference Counting). It works like assign in MRC (Manual Reference Counting). These properties won't be retained. Usually, you'd want to use such properties for delegates, because they don't need an owner which retains them.
weak properties are like unsafe_unretained, except that they work a bit smarter. When the object assigned to the property is released, a weak reference automatically becomes nil, to avoid crashes when sending messages to that object (its memory address).
unsafe_unretained properties don't do this. They will always hold on to the memory address (unless you manually change it) assigned to it, regardless of the object associated to that address. Weak references can prevent crashes in such a case, but the result still won't be as expected. If your code is organized and well-written, this shouldn't happen.
So why would you use unsafe_unretained instead of weak? Weak references are only available on iOS 5 and higher, so if you're building an ARC app targeting iOS 4, you need to use unsafe_unretained properties. And again, sending messages to a released property isn't anything you want to have in any code. If your code is well organized then you shouldn't have any problems with this.
Previously to ARC, one might specify a delegate or other reference-to-parent property as assign to prevent retain cycles. With the introduction of ARC and the newer compilers you would instead use unsafe_unretained.
So you use it any time you do not need ownership of the reference, and when you don't need or want to use the new weak reference type (which nulls out the reference when it is deallocated).
Here is a specific use case for unsafe_unretained. Say two classes reference each other, one direction being strong and the other direction weak. During dealloc of the first class the weak reference to it from the second class will already be nil, preventing proper cleanup to take place. Replacing the weak reference with an unsafe_unretained reference will solve this issue. See the code sample below:
#class Foo;
#interface Bar: NSObject
//Replacing weak with unsafe_unretained prevents this property from becoming nil during Foo.dealloc
#property (nonatomic, weak) Foo *foo;
- (id)initWithFoo:(Foo *)foo;
#end
#interface Foo : NSObject
#property (nonatomic, strong) Bar *bar;
- (void)startObserving;
- (void)endObserving;
#end
#implementation Bar
- (id)initWithFoo:(Foo *)foo {
if ((self = [super init])) {
self.foo = foo;
//Start observing
[self.foo startObserving];
}
return self;
}
- (void)dealloc {
//Since foo is a weak property, self.foo may actually be nil at this point! See dealloc of class Foo.
[self.foo endObserving];
}
#end
#implementation Foo
- (id)init {
if ((self = [super init])) {
self.bar = [[Bar alloc] initWithFoo:self];
}
return self;
}
- (void)dealloc {
//This will trigger the deallocation of bar. However, at this point all weak references to self will return nil already!
self.bar = nil;
//endObserving is never called, because Bar.foo reference was already nil.
}
- (void)startObserving {
NSLog(#"Start observing");
}
- (void)endObserving {
NSLog(#"End observing");
}
#end
unsafe_unretained does not interact with memory management at all. In ARC, the following code
{
__strong id obj = someObject;
obj = someOtherObject;
}
is equivalent to
{
id obj = [someObject retain];
[obj release];
obj = [someOtherObject retain];
[obj release];
}
in a non-ARC environment. So strong references keep the object alive. If you assign them a reference to another object, the old reference is first released. The same thing happens if such a reference goes out of scope. Note that references are strong by default, so usually you never have to use __strong unless you want to emphasize that a variable is strong.
A weak reference won't keep the object alive and becomes nil if the retain count of the object last assigned to it becomes zero.
__weak id wobj = nil;
{
__strong id obj = [Object new];
wobj = obj;
// wobj points to the same object as obj
}
// wobj is nil again
Inside the scope obj keeps the object alive and thus wobjc points to the same object as obj. But when obj goes out of scope, the object is released and as that was the only strong reference to it, is deallocated. As a result wobj becomes nil.
An unsafe_unretained retain reference is just a pointer to the object that has no knowledge about Obj-C memory management at all. The code
_unsafe_unretained id wobj = nil;
{
__strong id obj = [Object new];
wobj = obj;
// wobj points to the same object as obj
}
// wobj points to the memory address where an object used to be.
// This object has been deallocated! wobj is a dangling pointer!
// Trying to access the object via wobj may crash the app or cause
// other undefined behavior.
is equivalent to
id wobj = nil;
{
id obj = [Object new];
wobj = obj;
[obj release];
}
in a non-ARC environment. wobj won't be nil but the object it used to point to has already been dealloced and the memory may not even belong to the process anymore or it may have been recycled to store another object or any kind of allocated data (e.g. using malloc()).
Usually you want to use weak for references that don't keep the object alive. A typical situation where this is a problem is if object A has a strong references to object B A->B, and the other way round B->A. That is a retain cycle and now neither object A nor B will ever get released again, because A keeps B alive and B keeps A alive, and that is still true if nobody else has any reference to either A or B, both objects will always have a retain count of at least one. To fix that, one of both must have a weak reference to the other one.
E.g. if you write a XML parser, then XML nodes will have strong references to all their sub-nodes, to keep those alive and accessible but sub-nodes typically have a reference to their parent node and that would then be a weak node. That way you can get back to the parent node from any sub-node but they don't keep the parent alive, so if nobody else does (neither its parent nor any external reference), the parent node dies and the sub-nodes of it die with it.
Usually the only reason to use unsafe_unretained is performance. First of all, every object has a linked list containing all the address pointers of weak variables pointing to this object, so when the object dies, all these variables can be set to nil. Managing that linked list consumes time and the list itself consumes memory. Then every weak reference must temporarily become strong to ensure an object won't be released why you call a method on it. And finally, all of this must happen thread-safe, so it will always involve locking, even if your process is single threaded.
__weak id obj = someObject;
[obj performMethod];
obj = nil;
in fact is complex code behind the scenes and roughly equivalent to
lock(memlockOf(someObject));
id obj = someObject;
addWeakRefToLinkList(someObject, &obj);
unlock(memlockOf(someObject));
lock(memlockOf(obj));
id temp = [obj retain];
unlock(memlockOf(obj));
[temp performMethod];
[temp release];
lock(memlockOf(obj));
removeWeakRefFromLinkList(obj, &obj);
obj = nil;
unlock(memlockOf(obj));
And keep in mind that C pointers cannot be weak, so they are always unsafe_unretained. If you do this
id obj = [Object new];
void * cptr = (__bridge void *)obj;
Then cptr is in fact an unsafe_unretained reference to the object. You can make a C reference "quasi strong" if increase the retain count
id obj = [Object new];
void * cptr = (__bridge_retained void *)obj;
this is equivalent to
id obj = [Object new];
void * cptr = (void *)[obj retain];
in a non-ARC environment. The retain counter is increased by one and thus ARC will never release that object, as even if all ARC references go away, the object has at least a retain counter of one left.
But now the object is never released at all, unless you balance that with transfer bridging:
{
id obj = (__bridge_transfer id)cptr;
// Use obj all you want but don't touch cptr after that!
}
which is equivalent to
{
id obj = (id)cptr;
// Use obj all you want but don't touch cptr after that!
[obj release];
}
in a non-ARC environment. It's important that "transfer" means you are transferring the ownership back to ARC and thus you must not touch the cptr variable after doing so, as now ARC decides when the object dies and it won't set cptr to nil when that happens. Transfer means "make a strong ARC reference out of it but don't do anything with the retain count", so the retain count is not increased but once the strong reference is lost, the retain count is decreased as usual and this balances the extra retain of the retained bridging where the retain count was just increased but nothing else did happen.

Why can I not initialise my variable without using self

I have the following variable defined:
#property (nonatomic, retain) NSMutableArray *arraySpeechSentences;
And I am trying to initialise it in the following way:
// Set the array of sentences to the stored array
NSMutableArray *speechSentences = [[NSMutableArray alloc] initWithArray:[tempDict objectForKey:key]];
arraySpeechSentences = speechSentences;
[speechSentences release];
When I try to call [arraySpeechSentences count] the application crashes. However, if I set the variable in the following way:
// Set the array of sentences to the stored array
NSMutableArray *speechSentences = [[NSMutableArray alloc] initWithArray:[tempDict objectForKey:key]];
self.arraySpeechSentences = speechSentences;
[speechSentences release];
I can call [arraySpeechSentences count] perfectly fine. I was under the impression that if you use self. it simply checks to see if variable is already set, and if so it will release the object before assigning it the new value. Have I got this wrong, and if so when should I be using self. to set values?
Thanks for any help,
Elliott
Using a setter (like self.foo = ... or [self setFoo:...]) does release the old value but it also retains the new value, which is needed in the example you give.
The issue is that you're alloc and init'ing your array, and then releasing it. This indicates you no longer need it. So, you should either use the setter (usually preferable) or don't release your array.
If you're not using ARC, you should type
arraySpeechSentences = [speechSentences retain];
because you're accessing the instance variable directly, which means the value of the instance variable arraySpeechSentences will be the address of the speechSentence object, which you just released, so which is an invalid pointer. The semantic you declared in the property doesn't have an effect on the instance variable itself.
When you type self.arraySpeechSentences, you're actually using a shortcut for the setter [self setArraySpeechSentences:speechSentences], which actually retains the value passed as parameter (if you synthesized the property, it is retained because you specified retain in the property declaration; if you wrote the accessor yourself, it is your job to ensure you retained the value).
I'll try to give a detail answer for this.
First when you use #property/#synthesize directive you create getter and setter methods around a variable.
In your case, the variable is called arraySpeechSentences (the compiler will create the variable for you) and you can access these methods (setters and getters) with self..
self.arraySpeechSentences = // something
is the same as
[self setArraySpeechSentences:something]; // setter
And
NSMutableArray* something = self.arraySpeechSentences;
is equal to
NSMutableArray* something = [self arraySpeechSentences]; // getter
In the first snippet of code
NSMutableArray *speechSentences = [[NSMutableArray alloc] initWithArray:[tempDict objectForKey:key]];
arraySpeechSentences = speechSentences;
arraySpeechSentences points to the same object speechSentences points to. But when you do [speechSentences release] you dealloc that object and now arraySpeechSentences is a dangling pointer. You receive a message sent to a deallocated instance I suppose. Try to enable Zombie to see it.
Speaking in terms of retain count, the array has a retain count of 1 when you do alloc-init.
But when you release it, the retain count goes to zero, the object doesn't exist anymore and you have a crash when you try to access arraySpeechSentences.
Instead, when you deal with properties, the policy applied to a variable is important. Since the property use a retain policy, when you set an object
self.arraySpeechSentences = // something
the retain count for the referenced object is increased. Under the hood, saying self.arraySpeechSentences = // something is equal to call the setter like
- (void)setArraySpeechSentences:(NSMutableArray*)newValue
{
// pseudo code here...
if(newValue != arraySpeechSentences) {
[arraySpeechSentences release];
arraySpeechSentences = [newValue retain];
}
}
The second snippet work since the retain count for your object is one when you do alloc-init, becomes two when you call self.arraySpeechSentences = and returns to one when you do the release. This time, the object is maintained alive since it has a retain count of 1.
If you have a property with a retain or copy policy, don't forget to release the object in dealloc like, otherwise you can have leaks.
- (void)dealloc
{
[arraySpeechSentences release];
[super dealloc];
}
To understand how Memory works I suggest to read MemoryManagement Apple doc.
P.S. Starting from iOS 5 there is a new compiler feature, called ARC (Automatic Reference Counting), that allows you to forget about retain/release calls. In addition, since it forces you to think in terms of object graphs, I suggest you to take a look into.
Hope that helps.

property assign

If I have one property like this, what is the diference of assign the value of the property of the first mode and the second mode?
#interface Prueba : NSObject{
CustomeClass *_cclass;
}
#property(nonatomic, retain)CustomeClass *cclass;
#end
#implementation Prueba
#synthesize cclass = _cclass
- (void)config{
// 1 This
self.cclass = [[CustomeClass alloc] init];
// 2 This or
CustomeClass *cc = [[CustomeClass alloc] init];
self.cclass = cc;
[cc release];
}
#end
:/
Your first example gives you an object with a retain count of two (wrong), whereas your second example gives you an object with retain count of one (right). The second method is preferred in non-ARC projects. Alternatively, you could also do either set the ivar yourself (which I don't like because you're not using the setter):
_cclass = [[CustomeClass alloc] init];
or use the setter as your examples do, but do an autorelease (which I don't like because you shouldn't defer your releases unless you have to):
self.cclass = [[[CustomeClass alloc] init] autorelease];
In your non-ARC project, your original second example is best (using a pointer, using your property's setter, then releasing your pointer), because for KVO you want to get in the habit of using the setter:
CustomeClass *cc = [[CustomeClass alloc] init];
self.cclass = cc;
[cc release];
There is no difference in the result except that in the second method you create an additional pointer. In both versions self.cclass will hold your object just fine.
The problem is that when you only release the object in your second mode, in the first mode you'll have a memory leak. Since the retainCount of an object is +1 when you allocate it, you assign a +1 object through your setter. This means, that you actually bump up the retainCount again. Now if you don't release the object after assigning it to your property, once it gets released from there the retainCount will only be reduced by 1. Thus letting an object with a retainCount of +1 float around in the memory, lost forever.
But because you are already asking about a better version, I want to introduce lazy instantiation to you. What you can do, is that you overwrite the getter method of the property in question and check if it has been allocated yet. If not, you allocate it inside your getter method and then return it. It would look something like this:
- (CustomeClass*) cclass
{
if(!_cclass)
{
_cclass = [[CustomeClass alloc] init];
}
return _cclass;
}
With this method you assign a +1 retained object to an internal variable, thus bypassing the setter and not increasing the retainCount. Also it's memory friendly, because you object only gets instantiated when you really need it. Now when you set your property to nil or some new object, the old object will be properly deallocated.
EDIT:
In response to Robert Ryan's comment I want to add the following:
This does not break KVO, or interfere with the assigned qualifies for your properties. If your property is marked as assign or weak, then lazy instantiation doesn't really make sense. If it's marked as retain or strong this way of instantiating an object is perfectly fine, especially when it is a property which you would assign anyway inside a config method.
Regarding KVO: the value which is assigned inside the getter can be seen as the initial/default value, so KVO still works. It will trigger when you use the setter to assign something else to the property. You wouldn't want KVO to trigger because of a default value, would you?

#property retain - iPhone

I am newbie to iPhone programming. I have the following doubt which is stopping me to go ahead. Please consider the following code:
---------.h------
#interface myClass: UIViewController
{
UIImage *temp;
}
#property (nonatomic, retain) UIImage *temp;
---------.m------
#interface myClass
#synthesize temp;
-(void) dealloc
{
[temp release];
[super dealloc];
}
The above is the only program code. Thats it ... nothing else. Do I need to declare [temp release] in dealloc method even though I am not using the property accessor method in my program at all. What if I don't declare [temp release] in dealloc. Will that create memory leak as I am releasing something which I haven't retained as I am not calling property accessor method.
Also when i print retain count for temp why does it show 0 even though it is getting retained in #property.
Thanks in advance
If no value has ever been assigned to (an instance of) myClass.temp, then there won't be a leak. But you should release it in your dealloc.
#property is only a declaration that instance of myClass will have this property. You need to assign it a value before that value gets retained.
myClass *instance = [[myClass alloc] init];
// instance will now retain the value passed in
// and is therefore responsible for releasing it
instance.temp = [UIImage imageNamed:#"whatever"];
// if instance is not retained anywhere else,
// its dealloc will be called
[instance release];
On a sidenote, you should give your classes names that start with an uppercase
letter, i.e. MyClass. Not required, but makes things clearer.
You can also use self.temp = nil; in your dealloc You're sorta not supposed but it kinda works better and looks cleaner. It's a bit of an iffy subject...
What you are doing is correct. Scroll to the "dealloc" section of this Apple Doc: Declared Properties
Soon, however, these properties will be cleaned up automatically when you synthesize them (in the next Cocoa update) -- that being said, a convention I have personally began to follow so that my code works in the future is setting self.temp = nil; in dealloc instead of sending a release message (read the apple doc i posted, it explains this). The accessor method created at runtime releases the object first, so for me and quite a few other devs, this is a better/safer way of cleaning up declared properties in our dealloc.
Your code is correct.
The general rule is that, for all variables you declare in #interface, you must clean them up in -dealloc. Some variables will need to be released, others just need to be nil'd out, depending on how you've declared the #property.
In your example above, temp may never have been given a value explicitly by you, but the ObjC runtime will have initialized the value of temp to nil when an instance of your class gets allocated.
Sending a -release to a nil object is generally not a problem, so the [temp release] is fine. It's a no-op. When temp has a non-nil value in -dealloc, the [temp release] gets to do its job of freeing up the memory.
If you need temp to have a non-nil value on creation, you'll need to implement the -init method and make sure it gets some value. While your class is legitimate & functional without an -init method, you really should get in the habit including one in every custom class you design.
You'll need the default initializer at a minimum: -init. You may also want to design a more detailed initializer that could be used to give your temp ivar an a value, like -initWithImage:
Here's what you should also be including in your class:
#implementation MyClass
...
- (id) init {
self = [super init];
if (self != nil) {
// The minimal default initializer.
// temp will already have a value of nil, so you don't need necessarily
// need to do anything more, unless temp needs a real value on initialization.
}
return self;
}
- (void) dealloc {
...
}
#end
To implement a more detailed initializer, which would be known as the designated initializer, you would to something like this:
#implementation MyClass
...
- (id) initWithImage:(UIImage *)newImage {
self = [super init];
if (self != nil) {
temp = [newImage retain];
}
return self;
}
// Implement the default initializer using your more detailed initializer.
- (id) init {
// In this default initializer, every new instance comes with a temp image!
return [self initWithImage:[UIImage imageNamed:#"foobar"]];
}
- (void) dealloc {
...
}
#end
Here, the designated initializer -initWithImage: is the authoritative initializer. All other initializers, including -init, get implemented using -initWithImage:.
You get to exercise a lot of discretion over whether to implement any initializers beyond the minimal default initializer. Maybe -init is good enough for your purposes. That's fine. Sometimes more detailed initializers make using the class more convenient. Experience (and the Force) will be your guide.
Note that I didn't use the generated property accessor in either initializer method. If you aren't required by circumstances, you should generally avoid using property accessors in -init methods and -dealloc, primarily because of potential pain-in-the-ass issues with side effects of automatic key-value coding notifications.
The initializer and dealloc methods play a special role in a class. As the class designer, it is your responsibility to set and clean up instance variables in these methods. A good rule of thumb is to leave the use of synthesized property accessors for the callers of your class, and the implementation of other methods in the class.
When doing initialization of an instance, or deallocation, you can and should touch the ivars directly. They're yours. You declared them, so you can handle them directly. When implementing other methods in your class, you generally should use the property accessors.
JeremyP's link to the Cocoa Conceptual documentation on objects is a good one. You should definitely read the sections on Objects, and periodically re-read it as you gain more experience writing custom classes of your own. Eventually, it will all start making sense.

Objective-C Setter Memory Management

Still a little confused about Objective-C memory management. I think my confusion stems from what exactly the autorelease means.
NSString *theBackendResponse = [[NSString alloc] initWithData:receivedData encoding:NSASCIIStringEncoding];
NSDictionary *accountDictionary = [theBackendResponse propertyList];
[viewController setAccountDictionary:accountDictionary];
Now, what should I do with the accountDictionary in the setAccountDictionary method of my view controller? Right now I just set the instance variable "accountDictionary" to whatever is returned. Should I set it to a retained one, and then release the one that's returned? What should my setter code block look like, given that NSString's propertyList method is autoreleased?
By the way, if I release theBackendResponse, will I lose the accountDictionary? I assume not...
Calling [objectInstance autorelease] adds an object to the current NSAutoreleasePool. When that pool receives a drain message, it sends a release to all the objects in the pool. If any of those objects' retainCount reaches 0, they are deallocated at that point. The purpose of autorelease is to allow you to mark an object to be released "some time in the future". This is especially useful for things like methods that return a newly allocated object but want to release it so that the caller doesn't have to take ownership of the returned object. A method might look like this:
- (id)myMethod {
id myObj = [[SomeClass alloc] init];
...
return [myObj autorelease];
}
The caller of myMethod would then retain the return value if they wanted to take ownership of the returned value or ignore it if not. When the current NSAutoreleasePool is drained, myObj will get a release message. If no other objects own it (i.e. have sent it a retain message), it will get deallocated.
All of this is explained in the Cocoa Memory Management Programming Guide. Even if you've already read it, it's always worth an other read.
So, to answer your questions:
First, you should release theBackendResponse. You will leak memory if you do not. You don't need to know what accountDictionary does with the string: if it needs to keep a reference it will have retained theBackendResponse. You have an ownership of theBackendResponse because you alloc'd it, so you must relinquish that ownership (via release or indirectly via autorelease).
Second, you must retain or copy the argument to setAccountDictionary: if you want to keep a reference to that object or value respectively. The standard setter method looks something like this (assuming you do not need atomic semantics):
-(void)setAccountDictionary:(NSDictionary*)newDict {
if(newDict != accountDictionary) {
id tmp = accountDictionary;
accountDictionary = [newDict copy]; //Since newDict may be mutable, we make a copy so that accountDictionary isn't mutated behind our back.
[tmp release];
}
}
You must also remember to release accountDictionary in the dealloc method:
- (void)dealloc {
[accountDictionary release];
[super dealloc];
}
Since you appear to be using NSViewController, I assume you're on Leopard (OS X 10.5) in which case, you should probably be using #property and the #synthesized getter/setter if possible. To do this, add a
#property (copy,readwrite) NSDictionary * accountDictionary;
declaration to the class #interface. And add a #synthesize accountDictionary; directive in the #implementation block for your controller class.
In general, one object or method should not have to care about how another is managing memory. The fact that somebody else has autoreleased something is irrelevant to you. It's simpler to think of the concept of ownership. So retain and some other methods claim ownership, and release and autorelease relinquish it. If an object needs to keep a reference to another, it should claim ownership for as long as it needs. Thus, setter methods usually either retain or copy the new value and release or autorelease the old value.
I strongly recommend reading the Cocoa memory management guidelines. They're not all that long or complicated, and it's very important to understand them.
The set accessor method should always copy / retain the incoming value before releasing the old, in the case where the old value is the only object that owns the new value:
-(void)setAccountDictionary:(NSDictionary*)newDict {
id old = accountDictionary;
accountDictionary = [newDict copy];
[old release];
}
If accountDictionary referred to newDict and the retain count for newDict was 1, the call to [accountDictionary release] before the call to [newDict copy] would cause the retain count to got to 0 and therefore release newDict.
As an example of incorrect code, where we release the old dictionary and then copy the new dictionary:
-(void)setAccountDictionary:(NSDictionary*)newDict {
[accountDictionary release];
accountDictionary = [newDict copy];
}
and have the following code:
NSDictionary *dict = [obj accountDictionary];
[obj setAccountDictionary:dict];
It's contrived, but it demonstrates that in the setter, accountDictionary and newDict refer to the same instance. If the retain count is 1, the [accountDictionary release] line will decrease the retain count to 0, and thus release the instance from memory. [newDict copy] will now refer to an invalid instance.
Apple describes several concepts when implementing accessors: Memory Management Accessor Methods
If you can use Objective-C 2.0, I would go with properties and dot syntax.
Properties are new in Objective-C 2.0 and provide auto accessor generation.
In the .h File:
#property (retain) NSDictionary* accountDictionary;
In the implementation:
#synthesize accountDictionary;
Synthesize generates accessor methods for your NSDictionary. (If you want to provide your own implementation, you could also do that)