应该释放一个对象并将其设置为nil是原子的吗?

时间:2011-12-19 20:01:13

标签: objective-c ios multithreading cocoa-touch

我是Objective C的新手。我在许多iPhone / iPad应用程序中看到,在释放一个对象之后,它将被设置为nil。

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

我认为这样做是为了不让指针引用一个现在已经解除分配的内存位置。现在假设以下情况:

//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

我想知道这种情况是否可能?如果是,是否有办法使释放/零原子?

3 个答案:

答案 0 :(得分:5)

这实际上并不完全正确

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

你应该写简单

self.obj = nil;

将调用将释放前一个实例的setter。

答案 1 :(得分:4)

是的,它可能会爆炸。考虑一下您的代码示例。

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

您使用self.obj表示您正在引用accessor / mutators方法而不是直接访问您的对象。您可能会将“obj”声明为保留属性。你的.h就像是......

@property (retain) Something *obj;

和你的.m

@synthesize obj;

如果您稍后使用@synthesize创建的方法释放您的对象,那么您就是安全的。

[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;

如果你回顾我上面指定的属性,你会注意到我没有放入常见的nonatomic。这不是偶然的。看一下Apple的docs

  

默认情况下,属性是原子的,因此合成访问器提供对多线程环境中属性的强大访问 - 也就是说,无论其他线程同时执行什么,始终完全检索或设置从getter返回的值或通过setter设置的值。

答案 2 :(得分:1)

您可以在@synchronized块中包围这两个操作,以确保在离开块之前完成两个操作:

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

如果可能访问该变量的任何其他线程也在同一个锁对象周围同步,则不应遇到任何问题。