Accessor methods and (auto)release: conclusion
Accessor methods and (auto)release: conclusion
- Subject: Accessor methods and (auto)release: conclusion
- From: Ondra Cada <email@hidden>
- Date: Mon, 5 Aug 2002 23:15:12 +0200
Hello all,
since the question proved to be suprisingly tricky, I've tried to compile
a (reasonably) complete sum, with a very kind help of Ali Ozer
(nevertheless, any potential errors in this text are completely mine).
For diverse situations, diverse kind of accessors might be needed. For a
vast majority of cases though the following patterns should help:
A: normal, not thread-safe code
===============================
(A.i) simple objects, where the efficiency of a getter is very important
-getter {
return ivar;
}
-(void)setter:newObject {
[ivar autorelease];
ivar=[newObject copy]; // or retain, depending on object & usage
}
You should also use [ivar autorelease] (instead of release) in your
-dealloc method, for the same reason you are autoreleasing in the setter:
so that the vended object would survive setting another or releasing the
vendor. You might consider using [self setter:nil] in -dealloc instead of
explicit (auto)releasing, for it would release the ivar the proper way
"automatically", depending on the setter you actually use.
If the class is meant to be *really* straighforward (say, a very plain
NSArray-like container), you might -- for simplicity's sake -- want to use
[ivar release] in -dealloc and the A.ii setter (shown below); do mention
explicitly in documentation though that programmers should retain what
they got!
(A.ii) normal objects (presumably a majority of classes)
-getter {
return [[object retain] autorelease];
}
-(void)setter:newObject {
if (ivar==newObject) return;
[ivar release];
ivar=[newObject copy]; // or retain, depending on object & usage
}
This way is more safe eg. in cases of nested autorelease pools; therefore
it is preferred anytime the getter's efficiency is not paramount. It is no
bug to use the A.i setter here, but it would be somewhat superfluous.
B: thread-safe code (now things begin to be really tricky)
==========================================================
First, some auxiliary stuff: you need a lock to protect the ivar,
presumably an NSLock in another instance variable. You should create it in
the -init... method; otherwise -- if created in another method
on-demand -- you should use another lock to ensure that different threads
won't create (and subsequently use) different locks.
-getter {
id val;
[lock lock];
val=[ivar retain];
[lock unlock];
return [val autorelease];
}
-(void)setter:newObject {
id val=[newObject copy]; // or retain, depending on usage
id old;
[lock lock];
old=ivar;
ivar=val;
[lock unlock];
[old release];
}
Whenever you want to use the ivar, don't do it explicitly -- use the
getter instead (or lock the usage). It ensures that the contents of ivar
you actually use won't be meantime released by another thread.
In case there is a high probability you might get back the vended object
(ie., in principle, [foo setter:[foo getter]]) and the -- in this case
superfluous -- copy would be too expensive, another setter can be used for
a price of an extra lock/unlock pair:
-(void)setter:newObject {
id val;
id old;
[lock lock];
if (ivar==newObject) {
[lock unlock];
return;
}
[lock unlock];
// this is the previous setter, used though only if necessary:
val=[newObject copy];
[lock lock];
old=ivar;
ivar=val;
[lock unlock];
[old release];
}
General note: these patterns are meant to be used in newly written code.
The current Cocoa frameworks for diverse -- mainly historical and
compatibility -- reasons often does not use them the most correct way,
even without a proper documentation; this will eventually change.
---
Ondra Hada
OCSoftware: email@hidden
http://www.ocs.cz
private email@hidden
http://www.ocs.cz/oc
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.