Ответ 1
Я знаю, что вы, вероятно, спрашиваете об общем случае использования переменных по потокам (в этом случае правила об использовании 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
Цель C - это надмножество C, и если вы когда-либо делали обратную разработку ObjC, вы узнаете, что код ObjC (вроде, не совсем) преобразуется в код C перед его компиляцией. Все вызовы [self method:object]
преобразуются в вызовы objc_msgSend(self, "method:", object)
, а self
- это C-структура с ivars и другая информация о времени выполнения в ней.
Это означает, что этот код не делает то, что вы можете ожидать.
-(void)doThing{
NSInteger results = something + self.count;
}
Просто доступ к something
- это не просто доступ к переменной, но вместо этого выполняется self->something
(поэтому вам нужно получить слабую ссылку на себя при доступе к ivar в блоке Objective C, чтобы избежать цикла сохранения).
Второй момент - объекты Objective C на самом деле не существуют. self.count
превращается в [self count]
, а self.count = 5
превращается в [self setCount:5]
. Объективные свойства C - это просто синтаксический сахар; удобство спасет вас от ввода текста и сделайте вещи немного лучше.
Если вы используете Objective C более нескольких лет назад, вы запомните, когда вам пришлось добавить @synthesize propertyName = _ivarName
в @implementation
для свойств ObjC, которые вы указали в заголовке. (теперь Xcode делает это автоматически для вас)
@synthesize
был триггером для Xcode для генерации методов setter и getter для вас. (если вы не написали @synthesize
Xcode, ожидали, что вы сами напишите установщик и получатель)
// Auto generated code you never see unless you reverse engineer the compiled binary
-(void)setCount:(NSInteger)count{
_count = count;
}
-(NSInteger)count{
return _count;
}
Если вы беспокоитесь о проблемах с потоками с помощью self.count
, вас беспокоит 2 потока, вызывающих эти методы сразу (без прямого доступа к одной и той же переменной сразу, поскольку self.count
на самом деле является вызовом метода не переменной).
Определение свойства в заголовке изменяет код, сгенерированный (если вы сами не выполняете настройку).
@property (nonatomic, retain)
[_count release];
[count retain];
_count = count;
@property (nonatomic, copy)
[_count release];
_count = [count copy];
@property (nonatomic, assign)
_count = count;
TL;DR
Если вы заботитесь о потоковой передаче и хотите, чтобы вы не прочитали значение на полпути через запись, происходящую в другом потоке, измените nonatomic
на atomic
(или избавьтесь от nonatomic
как atomic
по умолчанию). Который приведет к созданию кода таким образом.
@property (atomic, assign) NSInteger count;
// setter
@synchronized(self) {
_count = count;
}
Это не гарантирует, что ваш код является потокобезопасным, но (если вы только получаете доступ к представлению свойств, который он устанавливает и получатель), вы должны избегать возможности чтения значения во время записи в другом потоке. Подробнее об атомном и nonatmoic в ответах на этот вопрос.