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

Что такое GlobalActor?

1.0 Junior🔥 202 комментариев
#Язык Swift

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

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

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

Что такое GlobalActor в Swift

GlobalActor — это новый тип актора, представленный в Swift 5.5 вместе с фреймворком Swift Concurrency. В отличие от обычных (неназначенных) акторов, которые изолируют своё состояние через экземпляры, GlobalActor — это синглтон-актор, который обеспечивает изоляцию данных на глобальном уровне, обычно на уровне всего приложения или критического домена. Основная цель — предоставить потокобезопасный доступ к общим ресурсам из разных частей программы, используя механизм акторов, но без необходимости создавать экземпляры.

Ключевое отличие от обычного актора

Обычный актор изолирует свои свойства и методы для каждого экземпляра:

actor Counter {
    private var value = 0
    func increment() { value += 1 }
}
let counter = Counter() // изоляция для этого экземпляра

GlobalActor же существует в единственном экземпляре (синглтон) и управляет доступом к ресурсам, которые должны быть глобально синхронизированы:

@globalActor
actor MyGlobalActor {
    static let shared = MyGlobalActor() // синглтон-экземпляр
}

Зачем нужен GlobalActor?

  1. Изоляция глобального состояния: Защита общих ресурсов, таких как кэши, базы данных или сетевые менеджеры, которые используются во всём приложении.
  2. Обеспечение thread-safety: Гарантия, что код, исполняемый под этим актором, не будет вызывать data races.
  3. Упрощение миграции: Позволяет постепенно переносить legacy-код (например, блоки GCD) на модель акторов, аннотируя целые классы или методы.
  4. Контроль над выполнением: Все задачи, отправленные в глобальный актор, выполняются последовательно на его изолированном экземпляре (shared).

Как использовать GlobalActor

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

import Swift

// 1. Объявляем глобальный актор
@globalActor
struct ImageCacheActor {
    // 2. Обязательно реализуем синглтон shared
    actor ActorType { }
    static let shared: ActorType = ActorType()
}

// 3. Аннотируем глобальное состояние или функции
@ImageCacheActor
class ImageCache {
    private var cache: [String: UIImage] = [:]

    func getImage(for key: String) -> UIImage? {
        return cache[key]
    }

    func setImage(_ image: UIImage, for key: String) {
        cache[key] = image
    }
}

// 4. Использование: вызов методов будет автоматически изолирован
Task {
    let cache = ImageCache()
    await cache.setImage(UIImage(), for: "avatar")
    let image = await cache.getImage(for: "avatar")
}

Важные аспекты

  • Статическое свойство shared: Должно возвращать экземпляр актора, который будет использоваться для синхронизации. Обычно это вложенный actor (как в примере выше) или сам глобальный актор, если он объявлен как actor.
  • Аннотации: @GlobalActorName применяется к классам, свойствам, функциям или замыканиям. Это указывает компилятору, что доступ должен быть изолирован через shared-актор.
  • Взаимодействие с async/await: Как и с обычными акторами, вызовы к изолированным сущностям требуют await, так как компилятор гарантирует, что выполнение происходит в контексте актора.
  • Отличие от @MainActor: @MainActor — это предопределённый GlobalActor в Swift, который изолирует код на главной очереди. По сути, это встроенная реализация глобального актора для работы с UI.

Практический пример

Допустим, у нас есть логгер, который пишет в файл из разных потоков:

@globalActor
actor FileLoggerActor {
    static let shared = FileLoggerActor()
    private var fileHandle: FileHandle?

    func log(_ message: String) {
        // Запись в файл, защищённая от конкурентного доступа
    }
}

@FileLoggerActor
class Logger {
    static let shared = Logger()
    private init() {}

    func logEvent(_ event: String) {
        // Этот метод автоматически изолирован FileLoggerActor.shared
        print("Log: \(event)")
    }
}

// Использование из любой точки программы
Task.detached {
    await Logger.shared.logEvent("App started") // Безопасный доступ
}

Вывод

GlobalActor — это мощный инструмент в арсенале Swift Concurrency для управления глобальным состоянием. Он сочетает преимущества акторов (автоматическая синхронизация, отсутствие data races) с удобством синглтона. Однако важно использовать его обдуманно: чрезмерное применение может привести к serialize bottlenecks, если множество задач будет блокировано на одном акторе. В целом, это отличное решение для изоляции разделяемых ресурсов в многопоточных iOS-приложениях.