在Swift / SwiftUI中编程选择字典项

6bc51xsx  于 2023-04-19  发布在  Swift
关注(0)|答案(1)|浏览(111)

我有一个API,它基于用户的区域访问以以下格式返回可变对象项的字典:

[
  {
    "region": "Alaska",
    "cities": ["Anchorage","Juneau","Fairbanks", etc..],
  },
  {
    "region": "Michigan",
    "cities": ["Detroit","Grand Rapids","Warren city", etc..],
  }
]

我试图找到一种方法来设置区域为一个选择器的数组,并从第一个选择器的选择,使第二个选择器与城市选项。
为此,我将userdefaults中的区域设置为一个数组,并将其Map为如下(WORKING):

struct ContentView : View {
    @State region: String = ""

    var body: some View {
        let regions = response.map{$0.region}

        Picker("Region", selection: $region) {
            ForEach(regions, id: \.self) {
               Text("\($0)")
            }
        }
    }
}

现在,在上面的选择器的更改事件中,我需要启用第二个选择器,并使用响应中的城市值填充它,最好的方法是什么?感谢帮助

zbdgwd5y

zbdgwd5y1#

我已经解决了这个问题,如下所示:

struct ContentView: View {
    @StateObject private var store = Store()
    @State private var region: String = "All"
    @State private var city: String = "All"
    @State private var showCities: Bool = false

var body: some View {
    
    Form {
        Section(header: Text("Search")) {
             
            Picker("Region", selection: $region) {
                ForEach(store.regions ?? ["Nil"], id: \.self) {
                    Text("\($0)")
                }
            }
            .onChange(of: region, perform: { (region) in
                showCities = false
                Task {
                    do
                    {
                        try await store.fetchCities(region: region)
                        showCities = true
                    } catch {
                        print("\(error)")
                    }
                }
            })
            
            if showCities {
                Picker("City", selection: $city) {
                    ForEach(store.cities ?? ["Nil"], id: \.self) {
                        Text("\($0)")
                    }
                }
            }                
        }
    }
    .task {
        do
        {
            try await store.fetchRegions()
        } catch {
            print("\(error)")
        }
    }
}

Store有访问这些细节所需的函数(它们是编码的),但如果这些值可以改变应用程序的性能/功能,我建议将它们放在keychain中:

@MainActor
class Store: ObservableObject {

@Published var decodedResponse: AuthenticationResponse?
@Published var statuses: [String]?
@Published var regions: [String]?
@Published var cities: [String]?
    
func fetchRegions() async throws {
    let data = UserDefaults.standard.value(forKey: "signInResponse") as! Data
    let decoded = try PropertyListDecoder().decode(AuthenticationResponse.self, from: data)
    var options = decoded.locations.map{$0.name}
    options.insert("All", at: 0)
    regions = options
}

func fetchCities(region: String) async throws {
    print("[VIEW] region in fetch \(region)")
    
    let data = UserDefaults.standard.value(forKey: "signInResponse") as! Data
    let decoded = try PropertyListDecoder().decode(AuthenticationResponse.self, from: data)
    var options = decoded.locations.first(where: {$0.name == region})?.set
    options?.insert("All", at: 0)
    cities = options
}

希望这对某人有帮助。我不是Maven:)

相关问题