Swift api observable 没有等待就无法工作
Swift api observable not working without wait
您好,我正在 LocationsDataService
class 中从本地 api 获取数据,并将其分配为数据服务中的 @Published var
,然后在我的 LocationsViewModel
。例如,如果我等待 api 请求完成;
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
let locations = dataService.locations
self.locations = locations
}
然后位置会呈现在屏幕上。
这是我的数据服务class;
//
// LocationsDataService.swift
// MapTest
//
//
import Foundation
import MapKit
import Combine
class LocationsDataService: ObservableObject {
let token = "2|asOnUG27uCrcVuGxOO65kS25mX0nUSls5ApfemQy";
@Published var locations: [Location] = []
public var cancellable: AnyCancellable?
enum HTTPError: LocalizedError {
case statusCode
}
init() {
fetch()
}
func fetch() {
guard let url = URL(string: "http://localhost:8080/api/locations") else {
print("Invalid url...")
return
}
var urlRequest = URLRequest(
url: url
)
urlRequest.setValue(
"Bearer \(token)",
forHTTPHeaderField: "Authorization"
)
self.cancellable = URLSession.shared.dataTaskPublisher(for: urlRequest)
.tryMap { output in
guard let response = output.response as? HTTPURLResponse, response.statusCode == 200 else {
throw HTTPError.statusCode
}
return output.data
}
.decode(type: [Location].self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
.sink(receiveCompletion: { completion in
switch completion {
case .finished:
break
case .failure(let error):
fatalError(error.localizedDescription)
}
}, receiveValue: { locations in
self.locations = locations
})
}
}
这是我的视图模型
//
// LocationsViewModel.swift
// CoffeeShops
//
//
import Foundation
import MapKit
import SwiftUI
class LocationsViewModel: ObservableObject {
// all loaded locations
@Published var locations: [Location]
init() {
let dataService = LocationsDataService() // the init function will do the api call
self.locations = [Location(
name: "Amsterdam",
address: "Amsterdam",
latitude: 52.3721009,
longitude: 4.8912196,
description: "Amsterdam",
imageNames: [],
link: "https://en.wikipedia.org/wiki/Colosseum")]
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
let locations = dataService.locations
self.locations = locations
print(locations)
}
}
}
我不确定为什么在将 api 分配给 LocationsViewModel
中的位置之前需要明确等待 api,因为 LocationsDataService.locations
是 @Published var locations: [Location] = []
,因此我认为它会被观察到。显然,在我可以更新屏幕之前设置一个时间限制并不是很好,因为它可以在 1 秒或 5 秒内完成。知道我做错了什么吗?
ObservableObject
将使 SwiftUI 视图在 @Published
更改时更新视图。但是当你在另一个里面创建一个 ObservableObject
时,它不可能自动工作。
您实际上不需要 ObservableObject
来提供您的服务,您只需要 @Published
来提供您的服务 属性,并且您可以如何将它与您的视图模型同步:
private var cancellable: AnyCancellable?
init() {
cancellable = dataService.$locations.sink(receiveValue: { locations in
self.locations = locations
})
}
您好,我正在 LocationsDataService
class 中从本地 api 获取数据,并将其分配为数据服务中的 @Published var
,然后在我的 LocationsViewModel
。例如,如果我等待 api 请求完成;
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
let locations = dataService.locations
self.locations = locations
}
然后位置会呈现在屏幕上。
这是我的数据服务class;
//
// LocationsDataService.swift
// MapTest
//
//
import Foundation
import MapKit
import Combine
class LocationsDataService: ObservableObject {
let token = "2|asOnUG27uCrcVuGxOO65kS25mX0nUSls5ApfemQy";
@Published var locations: [Location] = []
public var cancellable: AnyCancellable?
enum HTTPError: LocalizedError {
case statusCode
}
init() {
fetch()
}
func fetch() {
guard let url = URL(string: "http://localhost:8080/api/locations") else {
print("Invalid url...")
return
}
var urlRequest = URLRequest(
url: url
)
urlRequest.setValue(
"Bearer \(token)",
forHTTPHeaderField: "Authorization"
)
self.cancellable = URLSession.shared.dataTaskPublisher(for: urlRequest)
.tryMap { output in
guard let response = output.response as? HTTPURLResponse, response.statusCode == 200 else {
throw HTTPError.statusCode
}
return output.data
}
.decode(type: [Location].self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
.sink(receiveCompletion: { completion in
switch completion {
case .finished:
break
case .failure(let error):
fatalError(error.localizedDescription)
}
}, receiveValue: { locations in
self.locations = locations
})
}
}
这是我的视图模型
//
// LocationsViewModel.swift
// CoffeeShops
//
//
import Foundation
import MapKit
import SwiftUI
class LocationsViewModel: ObservableObject {
// all loaded locations
@Published var locations: [Location]
init() {
let dataService = LocationsDataService() // the init function will do the api call
self.locations = [Location(
name: "Amsterdam",
address: "Amsterdam",
latitude: 52.3721009,
longitude: 4.8912196,
description: "Amsterdam",
imageNames: [],
link: "https://en.wikipedia.org/wiki/Colosseum")]
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
let locations = dataService.locations
self.locations = locations
print(locations)
}
}
}
我不确定为什么在将 api 分配给 LocationsViewModel
中的位置之前需要明确等待 api,因为 LocationsDataService.locations
是 @Published var locations: [Location] = []
,因此我认为它会被观察到。显然,在我可以更新屏幕之前设置一个时间限制并不是很好,因为它可以在 1 秒或 5 秒内完成。知道我做错了什么吗?
ObservableObject
将使 SwiftUI 视图在 @Published
更改时更新视图。但是当你在另一个里面创建一个 ObservableObject
时,它不可能自动工作。
您实际上不需要 ObservableObject
来提供您的服务,您只需要 @Published
来提供您的服务 属性,并且您可以如何将它与您的视图模型同步:
private var cancellable: AnyCancellable?
init() {
cancellable = dataService.$locations.sink(receiveValue: { locations in
self.locations = locations
})
}