避免使用ARC的这个悬空指针

时间:2013-04-10 18:51:34

标签: objective-c automatic-ref-counting

我有一个对象保存对象的strong引用:

@property (nonatomic, strong) NSObject *thing;

在其他地方,我有一个传递对象引用的方法:

[thirdObject doSomething:secondObject.thing];

在一个案例中(百万或十亿),第三个对象最终使用悬空指针,因为对象被交换并且没有所有者。

我可以通过这样做来避免这种情况吗?这与ARC不同吗?

NSObject *thing = secondObject.thing
[thirdObject doSomething:secondObject.thing];

如果没有,我该如何避免这种情况?

编辑:消息是“消息发送到解除分配的实例0xwhatever”

1 个答案:

答案 0 :(得分:5)

如果不应用某种线程安全性,则无法在多个线程上读取和写入属性。现在原则上,对于像字符串这样的简单对象,也许仅仅应用atomic就足够了。有关详细信息,请参阅What's the difference between the atomic and nonatomic attributes?

坦率地说,我真的不喜欢atomic。我知道它的作用,但它似乎是一种繁琐的方式来达到你真正想要的东西(并且经常会比你想要的少)。而且这不是一个非常普遍的解决方案;我无法自定义atomic访问者“一点”(比如添加setNeedsDisplay等)。

这就是我喜欢基于队列的访问器的原因。他们的工作多一点,但是他们对很多问题都有效。

@property (nonatomic, readwrite, strong) dispatch_queue_t thingQueue;
@property (nonatomic, strong) NSObject *thing;

- (id)init {
  ...
    _thingQueue = dispatch_queue_create("...", DISPATCH_QUEUE_CONCURRENT);
  ...
}

- (NSObject *)thing {
  __block NSObject *thing;
  dispatch_sync(self.thingQueue, ^{
    thing = _thing;
  });
  return thing;
}

- (void)setThing:(NSObject *)thing {
  dispatch_barrier_async(self.thingQueue, ^{
    _thing = thing;
  });
}

我喜欢这个系统的是它允许所有读者并行。当作家试图进行更新时,无论涉及多少读者,都保证不会饿死。它总是快速返回。当值发生变化时,队列中还有一个明确的点,以便在编写者之前请求值的读者将始终获得旧值,并且在编写者之后的读者将始终获得新值,无论有多少争用在队列中。

关键是getter是同步的,所以它会等到它可以获得值,并且setter包含一个屏障。屏障意味着“在我运行时,不会从此队列中安排其他块”。因此,您有一堆并行运行的读取器块,然后出现了setter屏障并等待所有读者完成。然后它单独运行,设置值,然后它后面的读者可以再次并行运行。