Xcode报错:FruitPicker’ initializer is inaccessible due to ‘private’ protection level
Xcode报错:FruitPicker’ initializer is inaccessible due to ‘private’ protection level

Xcode报错:FruitPicker’ initializer is inaccessible due to ‘private’ protection level

问题复现

在学习Picker绑定tag时,发现存在下述报错问题。

报错提示:

完整问题代码

import SwiftUI

// 定义一个自定义水果对象
struct Fruit: Identifiable {
    let id = UUID()   // 唯一标识符
    let name: String  // 水果名称
    let color: String // 水果颜色
}

struct FruitPicker: View {
    @State private var selectedFruitId: UUID // 绑定的是水果的唯一ID
    let fruits = [
        Fruit(name: "Apple", color: "Red"),
        Fruit(name: "Banana", color: "Yellow"),
        Fruit(name: "Orange", color: "Orange")
    ]
    
    var body: some View {
        VStack {
            Picker("Select a fruit", selection: $selectedFruitId) {
                ForEach(fruits) { fruit in
                    // 显示水果名称,但使用水果的唯一ID作为 tag
                    Text(fruit.name).tag(fruit.id)
                }
            }
            .pickerStyle(WheelPickerStyle())

            if let selectedFruit = fruits.first(where: { $0.id == selectedFruitId }) {
                Text("Selected fruit: \(selectedFruit.name), Color: \(selectedFruit.color)")
            } else {
                Text("No fruit selected")
            }
        }
    }
}

#Preview {
    FruitPicker(selectedFruitId: Fruit(name: "Apple", color: "Red").id)
}

经排查发现问题为selectedFruitId字段是@State属性,因为@State属性是SwiftUI用来管理视图状态的特殊属性,因此它是私有的。所以,Swift UI不允许从视图外直接初始化它的值,这也意味着,我们无法通过下面的代码

FruitPicker(selectedFruitId: Fruit(name: "Apple", color: "Red").id)

从外部传一个初始值给selectedFruitId,因此触发报错提示。

解决方案

正因为@State的特殊性,我们需要给@State属性一个默认值,

1、selectedFruitId改为可选类型,因此不需要从外部传参。

    @State private var selectedFruitId: UUID? // 绑定的是水果的唯一ID

    2、通过onAppear方法给selectedFruitId传参

    .onAppear {
        selectedFruitId = fruits.first?.id
    }

    修改完这两部分后,我们发现

    if let selectedFruit = fruits.first(where: { $0.id == selectedFruitId }) {
        Text("Selected fruit: \(selectedFruit.name), Color: \(selectedFruit.color)")
    } else {
        Text("No fruit selected")
    }

    这段代码不会跟着我们的Picker选择器变化。

    这作为本次报错所延伸的另一个问题,问题出现在下面这段代码中:

    Picker("Select a fruit", selection: $selectedFruitId) {
        ForEach(fruits) { fruit in
            // 显示水果名称,但使用水果的唯一ID作为 tag
            Text(fruit.name).tag(fruit.id)
        }
    }
    .pickerStyle(WheelPickerStyle())

    这个问题在于Picker的selection绑定的是selectedFruitId,因为我们调整selectedFruitId为可选。因此,我们在Picker的tag选项也必须是可选类型的UUID?,只有这样才能让与selection绑定的值类型一致。

    Picker("Select a fruit", selection: $selectedFruitId) {
        ForEach(fruits) { fruit in
            // 显示水果名称,但使用水果的唯一ID作为 tag
            Text(fruit.name).tag(fruit.id as UUID?)
        }
    }
    .pickerStyle(WheelPickerStyle())

    按照上述操作全部修改后,问题得到解决。

    完整代码

    import SwiftUI
    
    // 定义一个自定义水果对象
    struct Fruit: Identifiable {
        let id = UUID()   // 唯一标识符
        let name: String  // 水果名称
        let color: String // 水果颜色
    }
    
    struct FruitPicker: View {
        @State private var selectedFruitId: UUID? // 绑定的是水果的唯一ID
        let fruits = [
            Fruit(name: "Apple", color: "Red"),
            Fruit(name: "Banana", color: "Yellow"),
            Fruit(name: "Orange", color: "Orange")
        ]
        
        var body: some View {
            VStack {
                Picker("Select a fruit", selection: $selectedFruitId) {
                    ForEach(fruits) { fruit in
                        // 显示水果名称,但使用水果的唯一ID作为 tag
                        Text(fruit.name).tag(fruit.id as UUID?)
                    }
                }
                .pickerStyle(WheelPickerStyle())
    
                if let selectedFruit = fruits.first(where: { $0.id == selectedFruitId }) {
                    Text("Selected fruit: \(selectedFruit.name), Color: \(selectedFruit.color)")
                } else {
                    Text("No fruit selected")
                }
            }
            .onAppear {
                selectedFruitId = fruits.first?.id
            }
        }
    }
    
    #Preview {
        FruitPicker()
    }

    如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

    发表回复

    您的电子邮箱地址不会被公开。 必填项已用 * 标注