我有一个基本的API:
class API: ObservableObject {
@Published private(set) var isAccessTokenValid = false
@AppStorage("AccessToken") var accessToken: String = ""
@AppStorage("RefreshToken") var refreshToken: String = ""
func request1() {}
func request2() {}
}
通过.environmentObject(API())
传递给所有视图。所以在任何视图中都可以很容易地访问API来做http请求调用。
我也有一个视图模型来获取一些数据的视图出现:
class ViewModel: ObservableObject {
@Published var data: [SomeResponseType]
init() {
// do the request and then init data using the response
}
}
struct ViewA: View {
@StateObject private var model = ViewModel()
var body: View {
VStack {
model.data...
}
}
}
但在init()
中,ViewModel
中的API不可访问。
所以,为了解决这个问题,我找到了三个解决方案:
解决方案1:将API更改为Singleton:
class API: ObservableObject {
static let shared = API()
...
}
我们还应该将enviromentObject(API())
改为enviromentObject(API.shared)
。
在ViewModel中,它可以使用API。直接共享。
方案2:调用onAppear/task上的请求
struct ViewA: View {
@EnvironmentObject var api: API
@State private var data: [SomeResponseType] = []
var body: View {
VStack {}
.task {
let r = try? await api.request1()
if let d = r {
data = d
}
}
}
}
解决方案3:设置viewmodelonappear/task的API
class ViewModel: ObservableObject {
@Published var data: [SomeResponseType]
var api: API?
setup(api: API) { self.api = api }
requestCall() { self.api?.reqeust1() }
}
struct ViewA: View {
@EnvironmentObject var api: API
@StateObject private var model = ViewModel()
var body: View {
VStack {}
.onAppear {
model.setup(api)
model.requestCall()
}
}
}
尽管如此,我仍然认为他们不是一个SwiftUI方式。我的问题是一个XY问题。可能,根本问题是如何重构我的API
。但是我是SwiftUI的新手。
解决方案2是最好的。您还可以尝试/捕获异常并为错误消息设置@State
。
尽量避免使用UIKit样式的视图模型对象,因为在SwiftUI中View
数据结构加上@State
已经完成了这个角色。只有当你需要视图数据的引用类型时,你才需要@StateObject
,现在我们有.task
。