具有自定义吸气剂的原子特性

时间:2015-05-11 07:03:41

标签: objective-c multithreading cocoa atomic lazy-initialization

我有一个声明为:

的属性的类
if (is_array($new_array[$i][$j]) && array_key_exists('distanceTimeFromNextPoint', $new_array[$i][$j])) 
{
    // you can update it
}

我想懒惰地实例化它,所以请使用以下自定义getter:

@property (nonatomic, strong) NSMutableArray *links;

我的应用程序已经有所改进,现在可以从不同的线程访问该对象。我将声明更改为:

- (NSMutableArray *)links {

    if (!_links) {
        _links = [NSMutableArray array];
    }

    return _links;
}
  

这会生成编译器警告:可写原子属性不能   将合成的setter与用户定义的getter相结合。

我明白了 - 我想。 我的问题是,正确执行以下操作,以便使用自定义getter创建原子属性?

  • 创建我自己的实例变量_links
  • @property (atomic, strong) NSMutableArray *links;
  • 包裹我的吸气剂
  • 创建一个用户定义的setter,也包含在@synchronized

编辑:这是我的新自定义setter和getter的代码:

@synchronized

2 个答案:

答案 0 :(得分:4)

首先,仅仅因为可以从多个线程访问该属性并不意味着a)它需要是原子的,也不是b)使其成为原子足以使其成为线程安全的。

特别是,属性类型是NSMutableArray*,这意味着任何调用者都可以获得可变数组,并且可以不受限制地对其进行变更,这本质上是线程不安全的。基本上你应该从不创建一个具有可变类型的属性。对属性的所有更改都必须通过访问器方法,以便您可以控制或至少对更改做出反应。

其次,你的getter正在使用double-checked lock anti-pattern。在Objective-C等基于C语言中它是不安全的。不要那样做。

那就是说,你是正确的,如果你创建一个属性原子并且你实现了getter或setter,那么你必须实现它们,你也负责实现同步来强制执行原子性。使用@synchronized()是合适的,只要您不使用双重检查锁定方法。

但是你真的需要让你的线程安全地关于该属性(以及可以从多个线程访问的任何其他属性),这需要的不仅仅是使属性成为原子。

答案 1 :(得分:0)

我想知道你为什么想要一个二传手。而且我想知道为什么你希望这个属性是原子的。

如果你想要一个getter和一个setter,最简单正确的方法就是编写

- (NSMutableArray*)links
{
    @synchronized (self)
    {
        if (_links != nil) _links = [[NSMutableArray alloc] init];
    }
    return _links;
}

- (void)setLinks:(NSMutableArray*)links
{
    @synchronized (self)
    {
        _links = links;
    }
}