Основной актор – изолированное свойство ‘xxx’ не может быть использовано из Sendable замыкания.

Вопрос или проблема

У меня возникла проблема с моим фото-приложением после обновления до Swift 6. В приведенном ниже примере я получаю эту ошибку (Свойство ‘photoImage’, изолированное для главного потока, не может быть вызвано из замыкания Sendable). Кто-нибудь знает, как это исправить? Присваивание ему другого значения в .task при запуске тоже не работает.

import SwiftUI
import PhotosUI

@Observable
final class CameraModel {
    var thumbnail: String?
}

struct ContentView: View {
    @State var camera = CameraModel()
    @State var selectedItems: [PhotosPickerItem] = []
    var body: some View {
        PhotosPicker(selection: $selectedItems, photoLibrary: .shared()) {
           // Я получаю ошибку здесь
            photoImage
        }
    }
    
    
    @ViewBuilder
    private var photoImage: some View {
        if let thumbnail = camera.thumbnail {
            Image(thumbnail)
                .resizable()
                .aspectRatio(contentMode: .fill)
                .animation(.easeInOut(duration: 0.3), value: thumbnail)
        } else {
            Image(systemName: "photo.on.rectangle")
        }
    }
}

#Preview {
    ContentView(camera: CameraModel())
}

Просто пометьте ваш photoImage как nonisolated, потому что протокол View помечен как @MainActor, поэтому все его свойства привязаны к MainActor. Тип метки замыкания просто @Sendable label: () -> Label, это не изолированный контекст, поэтому вам нужно пометить nonisolated.

struct ContentView: View {
    //@State var camera = CameraModel()
    @State var selectedItems: [PhotosPickerItem] = []
    var body: some View {
        PhotosPicker(selection: $selectedItems, photoLibrary: .shared(), label: {
            photoImage
        })
    }
    
    
    @ViewBuilder
    nonisolated private var photoImage: some View { //<- отметьте здесь
        ...
    }
}

.

Ответ или решение

Ошибка "Main actor-isolated property ‘xxx’ cannot be referenced from a Sendable closure" возникает из-за обновлений в Swift 6, касающихся управления контекстом исполнения и параметрами потокобезопасности. Давайте разберем вашу проблему, чтобы понять, как ее решить.

Контекст ошибки

Как правило, данный тип ошибки свидетельствует о том, что код пытается получить доступ к свойству (или переменной), изолированному в контексте главного актора, из замыкания, помеченного как Sendable. Swift 6 усилил безопасность потоков, заставляя разработчиков явно указывать, что можно безопасно передавать между потоками.

В вашем коде вы используете свойство photoImage, которое является представлением, зависящим от состояния модели camera, в замыкании, переданном в PhotosPicker. Однако, поскольку PhotoPicker работает с контекстом, который может исполняться в другом потоке, Swift не разрешает доступ к свойствам, изолированным для главного актора.

Решение проблемы

Чтобы устранить данный конфликт, вы можете пометить ваше представление photoImage как nonisolated. Это позволит избежать ограничения доступа из замыкания, вызванного контекстом исполнения:

struct ContentView: View {
    @State var selectedItems: [PhotosPickerItem] = []

    var body: some View {
        PhotosPicker(selection: $selectedItems, photoLibrary: .shared()) {
            photoImage
        }
    }

    @ViewBuilder
    nonisolated private var photoImage: some View {
        if let thumbnail = camera.thumbnail {
            Image(thumbnail)
                .resizable()
                .aspectRatio(contentMode: .fill)
                .animation(.easeInOut(duration: 0.3), value: thumbnail)
        } else {
            Image(systemName: "photo.on.rectangle")
        }
    }
}

Подробное объяснение изменений

  1. Объявление nonisolated: Добавление этого ключевого слова указывает, что данный метод или свойство может быть безопасно вызвано из любого контекста, не нарушая правил безопасности потоков. Это позволяет вам избежать ошибок, связанных с изоляцией актора.

  2. Переменная @State: Обратите внимание также на то, что переменные состояния (@State) должны использоваться с осторожностью в контексте изоляции. Убедитесь, что данные, хранящиеся в ваших состояниях, не конфликтуют с потокобезопасностью.

Заключение

Использование конструкции nonisolated является одним из способов эффективно управлять доступом к изолированным свойствам в Swift 6. Если вы сталкиваетесь с аналогичными ошибками в будущем, всегда стоит проверять контекст, в котором выполняется ваш код, и использовать соответствующие модификаторы, чтобы соответствовать требованиям безопасности потоков.

Следуя этим рекомендациям, вы сможете устранить возникшую проблему и оптимизировать ваш код для работы в среде Swift 6.

Оцените материал
Добавить комментарий

Капча загружается...