В чем разница между atomic и nonatomic свойствами в Objective-C?

Ответ

Атрибуты atomic и nonatomic определяют потокобезопасность геттеров и сеттеров синтезированных свойств.

Атрибут Гарантии потокобезопасности Производительность Рекомендуемое использование
atomic (по умолчанию) Гарантирует целостность операции get или set. Чтение/запись значения завершатся полностью до доступа из другого потока. Ниже из-за накладных расходов на блокировку. Редко. Когда необходимо примитивное обеспечение целостности для отдельного свойства в многопоточной среде.
nonatomic Не дает гарантий. Одновременный доступ из нескольких потоков может привести к повреждению данных или сбоям. Выше, так как отсутствуют блокировки. Практически всегда для iOS/macOS, особенно для UI-компонентов, которые обновляются только в главном потоке.

Критически важное уточнение: atomic НЕ делает свойство или объект потокобезопасным. Он защищает только отдельную операцию чтения или записи, но не последовательность операций (например, «прочитать-изменить-записать»). Для настоящей потокобезопасности нужны более высокоуровневые механизмы (очереди, @synchronized, семафоры).

Пример объявления:

// Objective-C
@property (atomic, strong) NSString *atomicString; // Медленнее, базовая защита
@property (nonatomic, strong) NSString *nonatomicString; // Быстрее, стандартный выбор

Ответ 18+ 🔞

А, ну вот, опять про эту атомарную хуйню! Сидишь такой, пишешь свой прекрасный Objective-C код, и тут бац — нужно выбрать между atomic и nonatomic. А выбор-то, блядь, на самом деле проще, чем кажется, если не забивать себе голову ерундой.

Смотри сюда, вникай. Представь, что твоё свойство — это бутылка колы в холодильнике на общей кухне.

  • atomic (это дефолтный вариант, ёпта) — это как если бы к холодильнику была прикручена, блядь, защёлка. Один человек может или ВЗЯТЬ бутылку целиком, или ПОЛОЖИТЬ её целиком. Операция завершится полностью, прежде чем другой потянется. Целостность бутылки гарантирована — ты не получишь в руки полбутылки и три орешка. Но производительность, сука, ниже, потому что эта защёлка — она же блокировка, на неё время тратится.
  • nonatomic — это когда холодильник просто открыт. Легко, быстро, производительность — овердохуища. Но если два потока вломятся туда одновременно, один будет засовывать бутылку, а другой — вытаскивать, может случиться пиздец. Можешь получить разбитое стекло, облитые колой носки или вообще краш приложения.

И вот тут главный подвох, блядь, который все пропускают! atomic — это НЕ волшебная таблетка от всех потокобезопасных проблем! Это просто защита одной операции: ВЗЯТЬ или ПОЛОЖИТЬ. Он НЕ защитит тебя, если ты делаешь «взял, отхлебнул, поставил обратно». Другой поток может вклиниться, пока ты хлебаешь, и выпьет всё до дна. Для таких сложных дел нужны нормальные инструменты: GCD, @synchronized, семафоры — вот это всё.

Короче, практический вывод, который все давно выучили: На iOS/macOS почти всегда ставим nonatomic. Почему? Да потому что UI-компоненты обновляются с главного потока, а производительность — наше всё. Зачем тебе лишние блокировки для какой-нибудь UILabel? Правильно, нихуя не зачем.

А atomic оставляем для редких, особых случаев, когда нужно это примитивное, базовое «не раздробить значение» при доступе из разных углов. Но даже там потом обычно понимаешь, что нужна нормальная синхронизация.

Как это выглядит в коде? Да вот так, элементарно:

// Objective-C
@property (atomic, strong) NSString *atomicString; // Медленнее, для особых ценителей
@property (nonatomic, strong) NSString *nonatomicString; // Быстрее, стандарт де-факто для всех

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