Cocoa Threadsafe Mutable Collection Access

时间:2008-12-01 15:42:15

标签: objective-c cocoa cocoa-touch multithreading

我正在推荐的方式在我的一个对象上创建一个符合KVC / KVO标准的可变数组:

@interface Factory {
    NSMutableArray *widgets;
}
- (NSArray *)widgets;
- (void)insertObject:(id)obj inWidgetsAtIndex:(NSUInteger)idx;
- (void)removeObjectFromWidgetsAtIndex:(NSUInteger)idx;
@end

显然,这是一个棘手的线程安全问题。在insertremove方法中,我锁定数组访问以防止并发修改,如recommended

我的问题是,实施widgets访问者的正确方法是什么?这是我的实施:

- (NSArray *)widgets {
    [widgetLock lock];
    NSArray *a = [[widgets copy] autorelease];
    [widgetLock unlock];
    return a;
}

线程安全吗?

3 个答案:

答案 0 :(得分:2)

您的widgets访问者应该没问题,但您应该知道该数组中没有任何对象被锁定。因此,您可能会遇到尝试同时运行

等代码的问题
[[[myFactory widgets] objectAtIndex:7] setName:@"mildred"];

[myTextField setStringValue:[[[myFactory widgets] objectAtIndex:7] name]]; // mildred? or something else?

由于数组中的对象未锁定,您可能会遇到竞争条件或读者/作者类型问题。多线程不是一种快乐吗?

另一方面,对于KVC合规性,我建议实施objectInWidgetsAtIndex:countOfWidgets而不是widgets访问者。请记住,KVC建模关系,而不是数组属性。因此,您可以调用类似[myFactory mutableArrayValueForKey:@"widgets"]的内容来获取表示widgets属性的数组。

答案 1 :(得分:2)

您也可以使用语言中内置的锁定,而不是创建自己的锁:

- (NSArray *)widgets {
    @synchronized(widgets)
    {
        NSArray *a = [[widgets copy] autorelease];
        return a;
    }
}

并在访问widgets的所有其他方法中使用类似的锁定。 (传递给widgets的参数@synchronized是指实例变量,而不是方法。)

alex关于访问所包含对象的评论仍然适用。

答案 2 :(得分:0)

您需要锁定所有读写方法。如果你的插入和删除也是锁定的(就像你说的那样),那么访问器方法应该是这样的。