从"fetching"到"displaying"的过渡JSONAPI数据SwiftNode.js
The transition from "fetching" to "displaying" JSON API data Swift Node.js
我了解如何从 JSON API(实际上是我的本地服务器)“获取”数据,但我应该如何考虑从仅仅拥有数据到显示数据的管道在意见?我直觉上想要做的是“return”来自获取函数的数据,尽管我知道这不是 Swift URL 函数操作的范例。我的想法是,如果我可以“return”数据(作为结构),那么很容易将其传递到视图中进行可视化。
示例代码:
这是获取的结构 JSON 以及我想传递给视图的变量类型。
struct User: Codable {
let userID: String
let userName: String
let firstName: String
let lastName: String
let fullName: String
}
我希望 printUser 函数可以 return 而不是打印成功的获取。
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)
}
}
你不能只是“return”的原因是你的fetchUser
是异步的。这意味着它 可能 return 相对瞬时或可能需要很长时间(或根本没有完成)。因此,您的程序需要准备好应对这种可能性。当然,如您所说,“很容易传递到视图中以进行可视化”,但不幸的是,这不符合实际情况。
你可以做的(在你的例子中)是将 User
设置为可选——这样,如果它没有被设置,你可以显示某种加载视图,如果它 已经设置了(即你的async函数已经returned了一个值),你可以显示它。那看起来像这样:
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()
}
}
}
注意:如果这是我的程序,我可能会重构异步内容以使用 Combine,但这是个人偏好问题
我了解如何从 JSON API(实际上是我的本地服务器)“获取”数据,但我应该如何考虑从仅仅拥有数据到显示数据的管道在意见?我直觉上想要做的是“return”来自获取函数的数据,尽管我知道这不是 Swift URL 函数操作的范例。我的想法是,如果我可以“return”数据(作为结构),那么很容易将其传递到视图中进行可视化。
示例代码:
这是获取的结构 JSON 以及我想传递给视图的变量类型。
struct User: Codable {
let userID: String
let userName: String
let firstName: String
let lastName: String
let fullName: String
}
我希望 printUser 函数可以 return 而不是打印成功的获取。
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)
}
}
你不能只是“return”的原因是你的fetchUser
是异步的。这意味着它 可能 return 相对瞬时或可能需要很长时间(或根本没有完成)。因此,您的程序需要准备好应对这种可能性。当然,如您所说,“很容易传递到视图中以进行可视化”,但不幸的是,这不符合实际情况。
你可以做的(在你的例子中)是将 User
设置为可选——这样,如果它没有被设置,你可以显示某种加载视图,如果它 已经设置了(即你的async函数已经returned了一个值),你可以显示它。那看起来像这样:
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()
}
}
}
注意:如果这是我的程序,我可能会重构异步内容以使用 Combine,但这是个人偏好问题