Just a coder
Just a coder

Reputation: 16720

Should releasing an object and setting it to nil be atomic?

I'm new to Objective C. I see in many iPhone/iPad applications that after releasing an object, it would then be set to nil.

[self.obj release]
self.obj = nil; 

I assume this is done so as not to leave the pointer to reference a memory location that is now deallocated. Now assume the following situation:

//Thread #1 code
..some code
..some code
[self.obj release]
                  -------> Thread #2 runs //Thread #2 code
                                          ..some code
                                          if (self.obj){
                                            some code
                                          }
self.obj = nil;   <----- Thread #1 runs

I was wondering if this situation possible? And if it is, is there a way to make the release/nil atomic?

Upvotes: 1

Views: 166

Answers (3)

DBD
DBD

Reputation: 23233

Yes, it could blow up. Consider your code example.

[self.obj release];
self.obj = nil;

You use self.obj which means you are referencing accessor/mutators methods instead of accessing your object directly. Chances are you'd declare "obj" as a retained property. Your .h would be something like...

@property (retain) Something *obj;

and your .m

@synthesize obj;

If you later release your object by using the methods created by your @synthesize you are safe.

[self setObj:nil];
// or equally valid
self.obj = nil;
// Below is (almost) identical way to access, release and nil the variable directly.
// The major difference is you don't multi-threaded protection of your property
// declaration (explained below).
[obj release];
obj = nil;

If you look back at the property I specified above you'll notice I didn't put in the very commonly seen nonatomic. It wasn't by accident. Take a look at Apple's docs

Properties are atomic by default so that synthesized accessors provide robust access to properties in a multithreaded environment—that is, the value returned from the getter or set via the setter is always fully retrieved or set regardless of what other threads are executing concurrently.

Upvotes: 4

AndersK
AndersK

Reputation: 36082

this is actually not entirely correct

[self.obj release]
self.obj = nil;

you should write simply

self.obj = nil;

which will call the setter that will release the previous instance.

Upvotes: 5

Matthew W
Matthew W

Reputation: 307

You can surround both operations in an @synchronized block to ensure that both operations complete before leaving the block:

@synchronized(lockObject)
{
    [self.obj release];
    self.obj = nil;
}

Provided that any other threads that might access that variable also synchronize around the same lock object, you shouldn't run into any issues.

Upvotes: 1

Related Questions