我开始学习SwiftUI。现在,我正在考虑在ObservableObject
中映射API响应的最佳方法。
首先,这是API响应:
{
"food": [
"fish",
"meat"
],
"go": [
"London",
"Bangkok"
],
"party": [
"Family",
"Friends"
]
}
这是我的ObservableObject
:
struct MyViewModel: ObservableObject {
var food: [String]
var go: [String]
var party: [String]
func fetchTagMeResponse() {
let url = URL(string: "domain.com/api/tagmes/")
var result = nil
URLSession.shared.dataTask(with: url!) { (data, res, err) in
DispatchQueue.main.async {
// WHAT IS THE BEST WAY TO MAP IT?
}
}.resume()
return result
}
}
如您所见,在代码行中,我需要最好的方法来从API获取数据响应:
DispatchQueue.main.async {
// WHAT IS THE BEST WAY TO MAP IT?
}
我的解决方案
我正在考虑使用Decodable
,但我认为这不是最好的方法。因为如果我不再使用MyResponse
。没必要吗?
struct MyResponse: Decodable {
var food: [String]
var go: [String]
var party: [String]
}
如果你们对此有更好的解决方案,请告诉我。
答案 0 :(得分:1)
这是我的NetworkManager类,对我来说,这是在SwiftUI中处理API的最佳方法
class NetworkManager: ObservableObject {
var objectWillChange = PassthroughSubject<NetworkManager,Never>()
var courses = [Course](){
didSet{
objectWillChange.send(self)
}
}
init() {
guard let url = URL(string: "https://myDomain/courses") else{ return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
let courses = try! JSONDecoder().decode([Course].self , from: data)
DispatchQueue.main.async {
self.courses = courses
debugPrint(self.courses)
}
}.resume()
}
}
//这就是我绑定数据的方式。
struct ContentView: View {
@ObservedObject var networkManager = NetworkManager()
var body: some View {
NavigationView {
List {
ForEach(networkManager.courses, id: \.id) { course in
RowUI(course: course)
}
}
.navigationBarTitle(Text("Courses"))
}
}
}
答案 1 :(得分:1)
您可以使用Combine来这样做。顺便说一句,最好使用Apple生产的Codable来为您减轻辛苦。这是一个功能强大的工具。
import SwiftUI
import Combine
//MARK: - Your model
struct MyResponse: Identifiable, Codable {
let id: Int
var food: [String]
var go: [String]
var party: [String]
}
//MARK: - Your network manager
class NetworkManager: ObservableObject {
@Published var myResponseFood = [String]()
@Published var myResponseGo = [String]()
@Published var myResponseParty = [String]()
func fetchTagMeResponse() {
_ = URLSession.shared
.dataTaskPublisher(for: URL(string: "domain.com/api/tagmes/")!)
.map(\.data)
.decode(type: MyResponse.self, decoder: JSONDecoder())
.sink(receiveCompletion: { (completion) in
if case .failure(let error) = completion {
print("You have an error: \(error)")
}
}, receiveValue: { (object) in
//MARK: - Your map objects are here
self.myResponseFood = object.food
self.myResponseGo = object.go
self.myResponseParty = object.party
})
}
}
//MARK: - Your SwiftUI view
struct MyViewModel: View {
@ObservedObject var networkManager = NetworkManager()
var body: some View {
NavigationView {
List(networkManager.myResponseParty) { party in
Text(party)
}
}
.onAppear {
self.networkManager.fetchTagMeResponse()
}
}
}