Свойства Objective-c для примитивных типов

В Objective-C Имеет ли смысл когда-либо указывать свойство для примитивного типа как nonatomic?

Я задаюсь вопросом о разнице между этими двумя свойствами:

@property (nonatomic) BOOL myBool;
@property BOOL myBool;

3 ответа

Технически, ответ ДА, они разные, но практически НЕТ, если нет, если вы не пишете свои собственные методы доступа.

Позволь мне объяснить. Например, для свойства указателя объекта @property NSObject *foo есть четкое и важное различие в коде, который генерируется, если вы используете синтезаторы методов доступа. Это описано в документации Apple, где указано, что синтезированные средства доступа будут блокировать объект, если свойство является атомарным (если вы не укажете неатомарное, оно станет атомарным по умолчанию)

Итак, для свойств объекта. В двух словах: неатомичный - быстрее, но не потокобезопасен, атомарный (его нельзя указать, но он по умолчанию) - потокобезопасен, но потенциально медленнее.

(Примечание: если вы привыкли к Java, вы можете использовать nonatomic как бы не указав synchronizedи не указав nonatomic как указание synchronized, Другими словами атомарный = синхронизированный)

Но BOOL является примитивом - на самом деле символ со знаком C, поэтому доступ должен быть атомарным, без блокировки объекта, как указано в ответе Яно. Поэтому, когда вы синтезируете средство доступа, есть две возможности: 1: компилятор умный и видит, что свойство примитивно и избегает его блокировки, и 2: компилятор всегда блокирует объект для атомарных свойств

Насколько я вижу, это нигде не задокументировано, поэтому я попробовал это, используя опцию Generate->Assembly в XCode и сравнив ее. Ответ не был окончательным, но достаточно близким, чтобы сказать, что я почти уверен, что ответ № 1, компилятор умный. Я говорю это, потому что ассемблерный код, сгенерированный для атомарного свойства объекта, значительно отличается (в большей степени), чем для неатомарного свойства объекта: это весь код для блокировки объекта. С другой стороны, для свойства BOOL существовала только одна строка - один "mov", который не выглядит так, как будто он может иметь значение. Все еще интересно. Интересно, что другое отличие состоит в том, что атомарная версия BOOL имеет несколько дополнительных закомментированных планов для отладки - так что компилятор явно трактует это по-другому.

Тем не менее, сходство таково, что я бы сказал, что они одинаковы для практических целей.

Но они все еще технически различны и могут существенно отличаться в какой-то другой библиотеке, которую вы читаете (которую вы сами не кодировали), если вы не видите реализацию, и вот почему: у атомарных свойств есть контракт. В контракте говорится: "Если вы получите доступ к моему значению в нескольких потоках, я обещаю, что каждая настройка или операция получения завершится до того, как начнется любая другая".

Но вы говорите, что BOOL по-прежнему атомарен, не является ли этот контракт неявным?

Нет. Переменная BOOL естественно атомарна, но мы говорим о свойстве. Свойство может быть не синтезировано и может даже не иметь единственной переменной для его резервного копирования. Это на самом деле довольно часто. Рассматривать:

@property (getter=isEmptyThingo) BOOL emptyThingo;

...
- (BOOL)isEmptyThingo
{
    Thingo *thingo = [self deriveTheThingo];
    if ([thingo length] == 0) {
        return YES;
    }
    return NO;
}

кто знает, что происходит в deriveTheThingo!? Ладно, это немного надумано, но дело в том, что isEmptyThingo - наш геттер выглядит не очень атомно, не так ли? Что происходит, если один поток получает вещь, а другой поток вызывает, чтобы найти, пусто ли это.

Короче говоря: собственность не атомная. Поэтому мы должны заявить об этом.

Следовательно, мой оригинальный ответ квалифицирован: если вы пишете это свойство самостоятельно и используете @synthesize, то они, вероятно, одинаковы, но вы, как правило, не должны относиться к ним одинаково.

Как правило, если вам не нужна многопоточная поддержка - что обычно не требуется, если вы работаете в коде пользовательского интерфейса, таком как UIViewControllers, тогда просто объявите все это неатомным.

В x-битной архитектуре (например, 32-битной, 64-битной и т. Д.) Любое значение, равное x или менее битам, всегда будет считываться или записываться атомарно. Это свойство любой разумной аппаратной реализации.

Атомарное свойство по умолчанию означает, что значение свойства всегда устанавливается или получается целиком, независимо от того, что делают другие потоки. Это касается только свойств, которые превышают количество битов архитектуры. Nonatomic полностью игнорируется компилятором для любого другого типа.

Пример:

@property struct { int d; } flag;
@property (atomic) struct { float x; float y; } point;
@property (atomic,copy) NSString *s;
  • struct { int d; } уже атомарен, поэтому аксессоры не нуждаются во взаимном исключении.

  • struct { float x, float y} может быть в несовместимом состоянии, если бы оно не было атомным. Пример: настройка двух потоков {1,2} а также {3,4} может перекрывать запись, и структура может заканчиваться значением из каждого набора: {1,4},

  • Указатели хранятся в одной позиции памяти, но они требуют нескольких операторов для управления памятью.

Атомарные свойства способствуют безопасности потока, избегая условий гонки, которые приводят к противоречивым значениям или ошибкам управления памятью. Само по себе это не гарантирует безопасность потоков, потому что не решает другие проблемы, такие как тупик, голодание, видимость и т. Д.

Да. nonatomic не является ключевым словом управления памятью, оно связано с безопасностью потоков. Кроме того, по умолчанию свойства являются атомарными (без явного объявления их неатомарными), поэтому существует разница между двумя перечисленными вами объявлениями.

Другие вопросы по тегам