← Назад к вопросам

В чем разница между Atomic и Non-atomic?

1.6 Junior🔥 161 комментариев
#Управление памятью#Язык Swift

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Atomic и Non-atomic: Различия в Objective-C

Ключевое различие между atomic и non-atomic свойствами в Objective-C заключается в гарантии целостности данных (atomicity) при многопоточных операциях чтения и записи. Эта концепция относится к синхронизации доступа к свойству из нескольких потоков одновременно.

Atomic (по умолчанию)

Atomic свойство гарантирует, что операции чтения (getter) и записи (setter) являются atomic — то есть, они выполняются как единая, неделимая операция из точки зрения других потоков. Это предотвращает ситуации, когда один поток начинает читать значение, а другой поток в середине этого процесса изменяет его, что может привести к получению некорректного, частично измененного значения.

Как это работает:

Компилятор автоматически генерирует getter и setter для atomic свойств, которые используют внутреннюю синхронизацию (обычно через механизмы типа @synchronized или низкоуровневые замки). Это обеспечивает безопасность при конкурентном доступе.

// Пример atomic свойства (явно указано)
@property (atomic, strong) NSString *atomicString;

// Сгенерированный компилятором код setter (примерная логика)
- (void)setAtomicString:(NSString *)newString {
    @synchronized(self) {
        _atomicString = newString;
    }
}
  • Преимущества: Безопасность в многопоточных сценариях. Вы никогда получите "сломанное" значение из-за одновременного чтения и записи.
  • Недостаки: Небольшие накладные расходы на производительность из-за необходимости синхронизации при каждом обращении. Это может быть критично в высоконагруженных участках кода. Важно: Atomic не делает свойство полностью "thread-safe". Он защищает только отдельные операции чтения/записи, но не гарантирует корректность последовательных операций (например, если вы читаете значение, затем, основываясь на нем, выполняете вычисления и записываете новое значение — между этими двумя шагами другой поток может изменить исходное значение).

Non-atomic

Non-atomic свойство не обеспечивает никакой синхронизации. Его getter и setter — это простые присваивания и возвращения значений. Это максимально быстрая операция.

// Пример non-atomic свойства
@property (nonatomic, strong) NSString *nonAtomicString;

// Сгенерированный компилятором код setter (примерная логика)
- (void)setNonAtomicString:(NSString *)newString {
    _nonAtomicString = newString; // Просто присваивание, без синхронизации
}
  • Преимущества: Максимальная производительность, отсутствие накладных расходов на блокировки.
  • Недостаки: Потенциальная опасность в многопоточных сценариях. Если несколько потоков одновременно обращаются к свойству, возможны:
    *   **Частичные записи:** Для сложных типов данных (например, структур) возможно чтение некорректного промежуточного состояния.
    *   **Гонки данных (Race Conditions):** Непредсказуемое конечное состояние значения.
    *   **Красивые сбои (Crashes):** Особенно при работе с объектами типа `NSString` или `NSArray`, где внутренняя структура может быть повреждена.

Ключевые выводы и рекомендации для iOS разработчика

  1. Выбор в современной практике: В подавляющем большинстве случаев в iOS/macOS разработке используют nonatomic. Это стало стандартом по двум причинам:
    *   Производительность: накладные расходы atomic в мобильных приложениях, где важна скорость отклика UI, нежелательны.
    *   Архитектура: ответственность за thread-safe переносится на более высокий уровень. Разработчики обычно управляют многопоточностью через:
        *   Явные механизмы синхронизации (`dispatch_queue`, `NSLock`, `os_unfair_lock`).
        *   Принципы, например, выполнение всех изменений модели на конкретной очереди (например, background queue) и последующая безопасная передача результата на главную очередь для UI.
        *   Использование inherently thread-safe классов или структур данных.

  1. Где может быть полезно atomic? В очень специфических случаях, когда свойство представляет собой простой тип данных (int, BOOL, float) и к нему возможен доступ из множества потоков, но синхронизация на более высоком уровне неудобна или избыточна. Однако даже для простых типов atomic не защищает от логических race conditions (как описано выше).

  2. Правило для UIKit: Все свойства, связанные с UI, должны быть nonatomic. Объекты UIKit (например, UIView, UIViewController) по своей архитектуре не предназначены для безопасного изменения из нескольких потоков — все операции с ними должны выполняться на главной очереди (Main Thread). Использование atomic для них бесполезно и затратно.

Итог: Используйте nonatomic как default choice для всех свойств объектов. Многопоточную безопасность реализуйте на уровне архитектуры (через очереди GCD, семафоры, замки), а не на уровне отдельных свойств. atomic — это микро-оптимизация для thread-safety, которая часто дает накладные расходы без решения реальной проблемы конкурентного доступа.