我有一个声明为:
的属性的类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创建原子属性?:
@property (atomic, strong) NSMutableArray *links;
@synchronized
编辑:这是我的新自定义setter和getter的代码:
@synchronized
答案 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;
}
}