我知道你可能在询问跨线程使用变量的一般情况(在这种情况下,使用volatile
和锁的规则与ObjC和普通C相同)。然而,对于您发布的示例代码,规则略有不同。(我将跳过并简化事物,并使用Xcode来表示Xcode和编译器)
self.count = 0;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
self.count = 5;
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"%i", self.count);
});
}
我假设self是一个NSObject子类,就像这样:
。
@interface MyClass : NSObject {
NSInteger something;
}
@property (nonatomic, assign) NSInteger count;
@end
Objective C 是 C 语言的超集,如果您曾经对 ObjC 进行过反向工程,您会知道在编译之前 ObjC 代码(有点不一样)会转换为 C 代码。所有 [self method:object]
调用都会被转换为 objc_msgSend(self, "method:", object)
调用,而 self
是一个带有实例变量和其他运行时信息的 C 结构体。
这意味着这段代码并不能完全达到您的预期。
-(void)doThing{
NSInteger results = something + self.count;
}
访问something
不仅仅是访问变量,而是执行self->something
(这就是为什么在Objective C块中访问ivar时需要获取对self的弱引用以避免保留循环)。
第二点是Objective C属性并不存在。 self.count
被转换为 [self count]
,self.count = 5
被转换为 [self setCount:5]
。Objective C属性只是语法糖;它们方便了您的输入,使事情看起来更加美观。
如果您使用Objective C已经超过几年,您会记得当您在头文件中声明ObjC属性时必须添加@synthesize propertyName = _ivarName
到@implementation
中。(现在Xcode会自动为您完成)
@synthesize
是Xcode生成setter和getter方法的触发器。(如果您没有编写@synthesize
,Xcode希望您自己编写setter和getter)
-(void)setCount:(NSInteger)count{
_count = count;
}
-(NSInteger)count{
return _count;
}
如果您担心
self.count
的线程问题,那么您应该担心两个线程同时调用这些方法(而不是直接同时访问同一个变量,因为
self.count
实际上是一个方法调用而不是变量)。
头文件中的属性定义会改变生成的代码(除非您自己实现setter)。
@property (nonatomic, retain)
[_count release];
[count retain];
_count = count;
@property (nonatomic, copy)
[_count release];
_count = [count copy];
@property (nonatomic, assign)
_count = count;
简而言之
如果您关心线程,并且希望确保在另一个线程上进行写操作时不会读取一半的值,则将nonatomic
更改为atomic
(或者去掉nonatomic
,因为atomic
是默认值)。这将导致生成类似于以下代码的代码。
@property (atomic, assign) NSInteger count;
// setter
@synchronized(self) {
_count = count;
}
这并不能保证你的代码是线程安全的,但只要你只访问属性视图的setter和getter,就可以避免在另一个线程上进行写操作时读取该值的可能性。有关原子和非原子的更多信息,请参阅
此问题的答案。
self.count += 1
不是一个原子操作(self.count += 1
===self.count = self.count + 1
;在读取和写入之间可以发生任何事情)。 - Itai Ferbervolatile
并不确保您将读取到未缓存的值: https://dev59.com/tXRB5IYBdhLWcg3wpotm,https://dev59.com/J3bZa4cB1Zd3GeqPH6CW,https://dev59.com/6Gsz5IYBdhLWcg3weHuU?rq=1 (它只保证编译器不会优化掉读取操作)。 - Itai Ferber