Может ли подкласс класса, изолированного @MainActor, быть полностью не изолированным?
Нет. Подкласс класса, изолированного @MainActor, должен сохранять изоляцию @MainActor; снять её со всего подкласса нельзя. Отдельные члены при этом могут иметь собственную допустимую аннотацию nonisolated, но это не отменяет изоляцию самого типа.
Глобальные акторы появились в Swift Concurrency, чтобы компилятор мог выражать принадлежность состояния и операций конкретному последовательному контексту. @MainActor решает типичную проблему UI-кода: обновления интерфейса должны выполняться на главном акторе, а не произвольно из фоновых задач.
Наследование добавляет контракт совместимости. Если базовый тип обещает, что его состояние и методы защищены главным актором, полностью не изолированный подкласс не может безопасно использовать или переопределять этот контракт.
Представим базовый контроллер, состояние которого доступно только на MainActor, и подкласс, пытающийся объявить себя обычным многопоточным типом. Тогда внешний код мог бы обращаться к экземпляру через тип подкласса, не переходя на главный актор, хотя унаследованные члены по-прежнему требуют такой изоляции.
Это создало бы противоречивую модель доступа: один и тот же объект выглядел бы изолированным через базовый тип и не изолированным через подкласс. Поэтому Swift запрещает полностью снимать глобальную акторную изоляцию при наследовании.
Изоляция @MainActor является частью контракта класса. Подкласс должен быть изолирован тем же глобальным актором; другой глобальный актор или отсутствие глобального актора не являются совместимым вариантом.
Вызов showError() или доступ к title из фоновой задачи потребует корректного перехода на MainActor. После await выполнение может продолжиться не на том же физическом потоке, но изолированный участок всё равно будет выполняться в контексте главного актора.
Аннотация nonisolated у отдельного метода означает, что именно этот метод не использует изоляцию экземпляра. Она не превращает весь класс в не изолированный и не позволяет такому методу обращаться к изменяемому изолированному состоянию без дополнительной синхронизации.
Практическое следствие: если часть типа должна работать в фоне, её обычно выносят в отдельный actor, обычный Sendable-тип или сервис без UI-состояния. Попытка сделать весь подкласс не изолированным ради фоновой работы нарушает модель наследования; композиция разделяет ответственность безопаснее.
Есть @MainActor-контроллер экрана, которому нужно загружать данные. Вариант с синхронной загрузкой внутри контроллера блокирует главный актор и ухудшает отзывчивость интерфейса. Вариант с попыткой сделать подкласс не изолированным не компилируется и концептуально смешивает UI-состояние с фоновой работой.
Разумное решение — оставить контроллер и его наследников изолированными @MainActor, а сетевой или вычислительный сервис вынести в отдельный тип. Сервис может быть actor или принимать и возвращать значения, безопасные для передачи между задачами; контроллер обращается к нему асинхронно и изменяет UI только после возвращения в свой глобальный актор.
Так сохраняется единый контракт для иерархии UI-типов, а длительная работа не занимает главный актор. Цена решения — явная асинхронная граница и необходимость передавать между компонентами только безопасные для конкурентности данные.
@MainActor есть только у базового класса?Да. Для подкласса это не просто удобное наследование поведения, а ограничение модели изоляции: он должен оставаться связанным с тем же глобальным актором. Явное указание @MainActor в объявлении подкласса делает контракт очевидным и полезно для читаемости, но не меняет правило совместимости.
nonisolated?В отдельных случаях — да, если требования языка для этого члена выполнены. Такой метод не может напрямую читать или изменять изолированное состояние экземпляра; он должен работать только с независимыми данными или безопасными для передачи значениями. Это локальное исключение для члена, а не способ превратить подкласс в не изолированный тип.
@MainActor-класса не означает, что любой код внутри метода автоматически безопасен?Изоляция защищает доступ к состоянию через акторный контекст, но не делает произвольные внешние объекты безопасными. Если метод передаст изменяемый ссылочный объект фоновой задаче или сохранит его за пределами изолированного типа, гонка всё ещё возможна. Глобальный актор сериализует доступ к своему изолированному состоянию, но не распространяет эту защиту на объекты, которыми он не владеет через тот же контракт.