我有一个SwiftUI视图,该视图带有一个Hacker News API提交ID,然后在fetchStory()
中获取该项目的详细信息。
fetchStory()
完成其HTTP调用后,将更新视图上的@State private var url
,但是视图从不重新渲染以显示新值-始终显示初始空值。
为什么?
import Foundation
import SwiftUI
struct StoryItem: Decodable {
let title: String
let url: String?
}
struct StoryView: View {
public var _storyId: Int
@State private var url: String = "";
init(storyId: Int) {
self._storyId = storyId
self.fetchStory()
}
var body: some View {
VStack {
Text("(Load a webview here for the URL of Story #\(self._storyId))")
Text("URL is: \(self.url)") // this never changes!
}
}
private func fetchStory() {
let url = URL(string: "https://hacker-news.firebaseio.com/v0/item/\(self._storyId).json")!
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else {
print(String(error.debugDescription))
return
}
do {
let item: StoryItem = try JSONDecoder().decode(StoryItem.self, from: data)
if let storyUrl = item.url {
self.url = storyUrl
} else {
print("No url")
}
} catch {
print(error)
}
}
task.resume()
}
}
struct StoryView_Previews: PreviewProvider {
static var previews: some View {
StoryView(storyId: 22862053)
}
}
答案 0 :(得分:1)
类似这样的东西:
import SwiftUI
struct StoryItem: Decodable {
let title: String
let url: String?
}
class ObservedStoryId: ObservableObject {
@Published var storyId: String = ""
init(storyId: String) {
self.storyId = storyId
}
}
struct StoryView: View {
@ObservedObject var storyId: ObservedStoryId
@State var url: String = ""
var body: some View {
VStack {
Text("(Load a webview here for the URL of Story #\(self.storyId.storyId))")
Text("URL is: \(self.url)")
Text(self.storyId.storyId)
}.onReceive(storyId.$storyId) { _ in self.fetchStory() }
}
private func fetchStory() {
let url = URL(string: "https://hacker-news.firebaseio.com/v0/item/\(self.storyId.storyId).json")!
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else {
print(String(error.debugDescription))
return
}
do {
let item: StoryItem = try JSONDecoder().decode(StoryItem.self, from: data)
if let storyUrl = item.url {
self.url = storyUrl
} else {
print("No url")
}
} catch {
print(error)
}
}
task.resume()
}
}
并这样称呼它:
struct ContentView: View {
@ObservedObject var storyId = ObservedStoryId(storyId: "22862053")
var body: some View {
StoryView(storyId: storyId)
}
}
答案 1 :(得分:0)
解决您的问题:
init(storyId: Int) {
self._storyId = storyId
}
var body: some View {
VStack {
Text("(Load a webview here for the URL of Story #\(self._storyId))")
Text("URL is: \(self.url)") // this now works
}.onAppear(perform: fetchStory)
}
这为什么起作用,而不是您的代码, 我的猜测是:“ self.url”只能在特殊的SwiftUI View函数(例如onAppear())内进行更新/更改,而在其他地方则不会改变。