json - 从“获取”到“显示”JSON API 数据的转变 Swift Node.js
问题描述
我了解如何从 JSON API(实际上是我的本地服务器)“获取”数据,但我应该如何考虑从仅拥有数据到在视图中显示数据的管道?我直观地想做的是从获取函数中“返回”数据,尽管我知道这不是 Swift URL 函数操作的范例。我的想法是,如果我可以“返回”数据(作为结构),那么将很容易传递到可视化视图中。
示例代码:
这是获取的 JSON 的结构以及我想要传递给视图的变量类型。
struct User: Codable {
let userID: String
let userName: String
let firstName: String
let lastName: String
let fullName: String
}
我希望 printUser 函数可以返回而不是打印成功的获取。
func printUser() {
fetchUser { (res) in
switch res {
case .success(let user):
print(user.userName) // return here?
// I know it won't work, but that's what seems natural
case .failure(let err):
print("Failed to fetch user: ", err)
}
}
}
func fetchUser(completion: @escaping (Result<User, Error>) -> ()) {
let urlString = "http://localhost:4001/user"
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url) { (data, resp, err) in
if let err = err {
completion(.failure(err))
return
}
do {
let user = try JSONDecoder().decode(User.self, from: data!)
completion(.success(user))
} catch let jsonError {
completion(.failure(jsonError))
}
}.resume()
}
将采用用户结构的示例视图
struct DisplayUser: View {
var user: User
var body: some View {
Text(user.userID)
Text(user.userName)
Text(user.lastName)
Text(user.firstName)
Text(user.fullName)
}
}
解决方案
你不能只是“返回”的原因是你fetchUser
是异步的。这意味着它可能会相对即时地返回,或者可能需要很长时间(或根本没有完成)。因此,您的程序需要准备好应对这种可能性。当然,正如您所说,“很容易进入可视化视图”,但不幸的是,它不符合实际情况。
您可以做的(在您的示例中)将其设置User
为 Optional - 这样,如果尚未设置,您可以显示某种加载视图,如果已设置(即您的异步函数已返回值),您可以显示它。看起来像这样:
class ViewModel : ObservableObject {
@Published var user : User? //could optionally store the entire Result here
func runFetch() {
fetchUser { (res) in
switch res {
case .success(let user):
DispatchQueue.main.async {
self.user = user
}
case .failure(let err):
print("Failed to fetch user: ", err)
//set an error message here? Another @Published variable?
}
}
}
func fetchUser(completion: @escaping (Result<User, Error>) -> ()) {
//...
}
}
struct DisplayUser: View {
@StateObject private var viewModel = ViewModel()
var body: some View {
VStack {
if let user = viewModel.user {
Text(user.userID)
Text(user.userName)
Text(user.lastName)
Text(user.firstName)
Text(user.fullName)
} else {
Text("Loading...")
}
}.onAppear {
viewModel.fetchUser()
}
}
}
注意:如果这是我的程序,我可能会重构异步内容以使用组合,但这是个人偏好问题
推荐阅读
- c - 如何获取c程序的执行时间?
- rust - Rust 中逆变使用的例子是什么?
- html - 引导按钮网变圆
- docker - 尝试更改 docker data-root 失败 - 为什么
- javascript - 重复使用 blaze 模板,如何访问其他模板的辅助函数?
- html - 如何在引导固定导航栏中移动项目
- kotlin - 如何在 Kotlin 中使用泛型定义功能接口?
- mysql - Selenium python脚本工作但它没有点击或输入任何值firefox
- apache-spark - 为什么要在一个执行程序中对所有数据进行分区?
- javascript - JQuery 不会更新按钮上的微调器