Using PhotosPickerItem with Swift Concurrency (Strict Checking Enabled)

  Kiến thức lập trình

I’ve been updating my code to conform to Swift’s strict concurrency rules and I’m running into this problem that I haven’t been able to figure out. I’m hoping someone who’s a little more knowledgeable can help me out. This is the view I’m working on:

struct RecipeImage: View {
    @State private var selection: PhotosPickerItem?
    @Binding var imageData: Data?
    
    var body: some View {
        Group {
            if let data = imageData {
                if let uiImage = UIImage(data: data) {
                    VStack {
                        Image(uiImage: uiImage)
                            .resizable()
                            .scaledToFit()
                        
                        HStack {
                            Spacer()
                            PhotosPicker(selection: $selection, matching: .images) {
                                Text("Edit")
                                    .fontWeight(.medium)
                                    .padding(5)
                                    .frame(width: 75)
                                    .background(Color(UIColor.secondarySystemFill))
                                    .foregroundColor(.black)
                                    .clipShape(.capsule)
                            }
                            Spacer()
                        }
                    }
                }
            } else {
                PhotosPicker(selection: $selection, matching: .images) {
                    ZStack {
                        Color.gray
                        Image(systemName: Constants.Icons.PhotoRectangleFilled)
                            .resizable()
                            .scaledToFit()
                            .frame(width: 50, height: 50)
                            .foregroundColor(.white)
                    }
                }
                .frame(height: 300)
            }
        }
        .task(id: selection) {
            imageData = try? await selection?.loadTransferable(type: Data.self)
        }
    }
}

I’m getting the following warning inside the task portion (yellow underline on the s of selection?): Passing argument of non-sendable type 'PhotosPickerItem' outside of main actor-isolated context may introduce data races. I’m confused by this because the actor of the task should be the same as the view so it shouldn’t be being sent between contexts. It’s especially confusing because I can set imageData inside the task without issues.

I’ve tried the following things:

.onChange(of: selection) {
    Task { @MainActor in // tried it without @MainActor as well
        imageData = try? await selection?.loadTransferable(type: Data.self) // same warning
    }
}
.onChange(of: selection) { oldValue, newValue
    Task { @MainActor in // tried it without @MainActor as well
        imageData = try? await newValue?.loadTransferable(type: Data.self) // same warning
    }
}
.onChange(of: selection) { // tried this using task as well
    Task { @MainActor in // tried it without @MainActor as well
        let test = selection {
            imageData = try? await test.loadTransferable(type: Data.self) // same warning
        }
    }
}

I did this just to verify I can do something with the PhotosPickerItem inside the task/onChange:

.onChange(of: selection) { // tried this using task as well
    imageData = Data()
    selection = nil
}

Additionally, I tried creating a function (with @MainActor and not) that takes in a PhotosPickerItem and returns the Data:

.onChange(of: selection) {
    Task { @MainActor in // tried it without @MainActor as well
        imageData = await loadData(selection) // no warning here
    }
}

// tried it without @MainActor as well
@MainActor func loadData(_ item: PhotosPickerItem) async -> Data? {
    return try? await item.loadTransferable(type: Data.self) // same warning here
}

So as you can see, I’ve been trying a bunch of different things and have been getting the same warning. I’ve been researching things all day but have had no success in fixing this issue. I’m fairly new to Swift and would really appreciate some help on this.

New contributor

Jordan Herget is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

LEAVE A COMMENT