Вопрос или проблема
Здесь hasComplexWave
— это логическое значение @State
в представлении SwiftUI. Вот код, который его использует:
view.visualEffect { [hasComplexWave] content, proxy in
content.distortionEffect(
ShaderLibrary.complexWave(
.float(startDate.timeIntervalSinceNow),
.float2(proxy.size),
.float(0.5),
.float(8),
.float(10)
),
maxSampleOffset: CGSize(width: 100, height: 100),
isEnabled: hasComplexWave
)
}
Проблема в том, что это вызывает предупреждение в Swift 5 и ошибку в Swift 6, которая выглядит следующим образом:
Свойство основного актора ‘hasComplexWave’ не может быть использовано из замыкания Sendable; это ошибка в режиме языка Swift 6
Как лучше всего исправить эту ошибку?
Вы можете добавить “список захвата” в замыкание, чтобы избежать ссылки на свойство, изолированное в актере, внутри замыкания.
Таким образом, замените …
view.visualEffect { content, proxy in … }
… на:
view.visualEffect { [hasComplexWave] content, proxy in … }
Смотрите Списки захвата и Захват значений из Язык программирования Swift.
Попробуйте добавить @MainActor
view.visualEffect { @MainActor content, proxy in
content.distortionEffect(
ShaderLibrary.complexWave(
.float(startDate.timeIntervalSinceNow),
.float2(proxy.size),
.float(0.5),
.float(8),
.float(10)
),
maxSampleOffset: CGSize(width: 100, height: 100),
isEnabled: hasComplexWave
)
}
Ответ или решение
Чтобы использовать свойство @State из отправляемого замыкания в SwiftUI, необходимо учесть несколько аспектов, связанных с акторной моделью Swift. Ошибка, с которой вы столкнулись, связана с тем, что свойства, определенные как @State, изолированы на главном акторе, и их нельзя напрямую ссылаться из замыканий, которые объявлены как Sendable. Ниже приведены рекомендации по устранению этой проблемы.
Проблема
Ваш код содержит строку, где переменная hasComplexWave
, отмеченная как @State, используется в отправляемом замыкании:
view.visualEffect { [hasComplexWave] content, proxy in
content.distortionEffect(
ShaderLibrary.complexWave(
.float(startDate.timeIntervalSinceNow),
.float2(proxy.size),
.float(0.5),
.float(8),
.float(10)
),
maxSampleOffset: CGSize(width: 100, height: 100),
isEnabled: hasComplexWave
)
}
В Swift 6 это вызывает ошибку: "Main actor-isolated property ‘hasComplexWave’ cannot be referenced from a Sendable closure".
Решение
Есть несколько способов, чтобы решить эту проблему:
1. Использование списка захвата (Capture List)
Вы уже сделали шаг в правильном направлении, добавив список захвата:
view.visualEffect { [hasComplexWave] content, proxy in
content.distortionEffect(
ShaderLibrary.complexWave(
.float(startDate.timeIntervalSinceNow),
.float2(proxy.size),
.float(0.5),
.float(8),
.float(10)
),
maxSampleOffset: CGSize(width: 100, height: 100),
isEnabled: hasComplexWave
)
}
Однако такое решение все еще может не сработать, так как список захвата может просто ‘схватить’ ошибочное состояние hasComplexWave
.
2. Использование @MainActor
Для исправления ситуации можно добавить атрибут @MainActor
в объявление замыкания. Это позволяет явно указывать, что замыкание должно выполняться на главном акторе, обеспечивая безопасный доступ к свойствам, изолированным на этом акторе:
view.visualEffect { @MainActor content, proxy in
content.distortionEffect(
ShaderLibrary.complexWave(
.float(startDate.timeIntervalSinceNow),
.float2(proxy.size),
.float(0.5),
.float(8),
.float(10)
),
maxSampleOffset: CGSize(width: 100, height: 100),
isEnabled: hasComplexWave
)
}
Заключение
Учитывая вышеописанные методы, использование @MainActor
в замыкании представляется наиболее эффективным способом избежать проблемы, связанной с акторной изоляцией. Это решение гарантирует корректный доступ к свойствам, отмеченным как @State, что позволяет вашему коду компилироваться и выполняться без ошибок. Например, если вам нужно будет несколько раз использовать hasComplexWave
, хорошей практикой будет его объявление на уровне, доступном для вашего замыкания (если контекст позволяет).
Такое внимание к управлению состоянием и изоляции данных в SwiftUI помогает создать более надежное и безопасное приложение, с правильным управлением потоками выполнения и состоянием пользовательского интерфейса.