SwiftUI Picker desn';不要与观察对象绑定

SwiftUI Picker desn';不要与观察对象绑定,swiftui,bind,picker,observedobject,Swiftui,Bind,Picker,Observedobject,我试图用从外部API异步获取的数据填充选择器 这是我的模型: struct AppModel: Identifiable { var id = UUID() var appId: String var appBundleId : String var appName: String var appSKU: String } 获取数据并发布的类是: class AppViewModel: ObservableObject { private var

我试图用从外部API异步获取的数据填充选择器

这是我的模型:

struct AppModel: Identifiable {
    var id = UUID()
    var appId: String
    var appBundleId : String
    var appName: String
    var appSKU: String
}
获取数据并发布的类是:

class AppViewModel: ObservableObject {
    private var appStoreProvider: AppProvider? = AppProvider()
    @Published private(set) var listOfApps: [AppModel] = []
    @Published private(set) var loading = false

    fileprivate func fetchAppList() {
        self.loading = true
        appStoreProvider?.dataProviderAppList { [weak self] (appList: [AppModel]) in
            guard let self = self else {return}
            DispatchQueue.main.async() {
                self.listOfApps = appList
                self.loading = false
            }
        }
    }
    init() {
        fetchAppList()
    }
}
意见是:

struct AppView: View {
    @ObservedObject var appViewModel: AppViewModel = AppViewModel()
    @State private var selectedApp = 0

    var body: some View {
        ActivityIndicatorView(isShowing: self.appViewModel.loading) {
            VStack{
                // The Picker doesn't bind with appViewModel
                Picker(selection: self.$selectedApp, label: Text("")) {
                    ForEach(self.appViewModel.listOfApps){ app in
                        Text(app.appName).tag(app.appName)
                    }
                }
                // The List correctly binds with appViewModel
                List {
                    ForEach(self.appViewModel.listOfApps){ app in
                        Text(app.appName.capitalized)
                    }
                }
            }
        }
    }
}

当列表视图与观察到的对象appViewModel绑定时,选择器的行为方式不同。我不知道为什么。有什么帮助吗

我无法将其放入您的代码中,因为它不完整,但这里有一个示例。 选择器不是动态的。它们必须完全重新加载

class DynamicPickerViewModel: ObservableObject {
    @Published private(set) var listOfApps: [YourModel] = []
    @Published private(set) var loading = false

    fileprivate func fetchAppList() {
            loading = true
            DispatchQueue.main.async() {
                self.listOfApps.append(YourModel.addSample())
                self.loading = false
            }

    }
    init() {
        fetchAppList()
    }

}
struct DynamicPicker: View {
    @ObservedObject var vm = DynamicPickerViewModel()
    @State private var selectedApp = ""

    var body: some View {
        VStack{
            //Use your loading var to reload the picker when it is done
            if !vm.loading{
                //Picker is not meant to be dynamic, it needs to be completly reloaded
                Picker(selection: self.$selectedApp, label: Text("")) {
                    ForEach(self.vm.listOfApps){ app in
                        Text(app.name!).tag(app.name!)
                    }
                }
            }//else - needs a view while the list is being loaded/loading = true


            List {
                ForEach(self.vm.listOfApps){ app in
                    Text(app.name!.capitalized)
                }
            }

            Button(action: {
                self.vm.fetchAppList()
            }, label: {Text("fetch")})

        }
    }
}

struct DynamicPicker_Previews: PreviewProvider {
    static var previews: some View {
        DynamicPicker()
    }
}

我提交了错误报告FB7670992。苹果昨天做出回应,建议我在iOS 14 beta 1中确认这一行为。现在似乎已经解决了

struct ContentView: View {
    @ObservedObject var viewModel = ViewModel()

    var body: some View {
        Picker("", selection: $viewModel.wheelPickerValue) {
            ForEach(viewModel.objects) { object in
                Text(object.string)
            }
        }
        .pickerStyle(WheelPickerStyle())
        .labelsHidden()
    }
}
在哪里

struct对象:可识别{
设id=UUID().UUIString
让字符串:字符串
}
类ViewModel:ObservableObject{
专用变量计数器=0
@已发布的专用(集)变量对象:[Object]=[]
@已发布的var segmentedPickerValue:String=“”
@已发布的var wheelPickerValue:String=“”
fileprivate func nextSetOfValues(){
设newCounter=counter+3

对象=(如果你给我们一个可编辑的可复制的例子……我们会帮助你……但是你的代码甚至不能编译,因为你只发布了部分代码。请阅读并考虑这个:是的!!非常感谢!!(或者标记类型,如果您要像这里一样显式指定标记)。有趣的是,如果您使用
.pickerStyle(SegmentedPickerStyle())
,它确实会得到更新。(我确定您不需要分段选择器,所以这不是问题的答案,但它只是一个有趣的数据点。)感觉像是
PickerView
updateUI
缺少一个
reloadAllComponents
…FWIW,我提交了错误报告,FB7670992.FWIW,这种技术只有在
fetchAppList
实际需要一点时间的情况下才有效。例如,在您的示例中,
DispatchQueue.main.async
是不够的,但类似于
DispatchQueue.main.asyncAfter(截止日期:.now()+0.1)
是。我不确定我是否会说选择器“注定”不是动态的。这似乎只是一个疏忽/错误(因为为什么它会与分段选择器而不是轮式选择器一起工作)。
struct Object: Identifiable {
    let id = UUID().uuidString
    let string: String
}

class ViewModel: ObservableObject {
    private var counter = 0

    @Published private(set) var objects: [Object] = []
    @Published var segmentedPickerValue: String = ""
    @Published var wheelPickerValue: String = ""

    fileprivate func nextSetOfValues() {
        let newCounter = counter + 3
        objects = (counter..<newCounter).map { value in Object(string: "\(value)") }
        let id = objects.first?.id ?? ""
        segmentedPickerValue = id
        wheelPickerValue = id
        counter = newCounter
    }

    init() {
        let timer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { [weak self] timer in
            guard let self = self else { timer.invalidate(); return }
            self.nextSetOfValues()
        }
        timer.fire()
    }
}