[英]Why is my @AppStorage not working on SwiftUI?
我正在嘗試在我的項目中設置 @AppStorage 包裝器。
我正在從 JSON API(請參閱 DataModel)中提取文本,並希望將結果存儲在 UserDefautls 中。 我希望獲取數據。OnAppear 並將其存儲到@AppStorage 中。 當用戶點擊“獲取下一個文本”時,我想要獲取一首新詩,並使用最新的文本數據更新@AppStorage,(這將刪除過去存儲的詩)。
目前,下面的代碼構建但不在Text(currentPoemTitle)
中顯示任何內容。
數據 Model
import Foundation
struct Poem: Codable, Hashable {
let title, author: String
let lines: [String]
let linecount: String
}
public class FetchPoem: ObservableObject {
// 1.
@Published var poems = [Poem]()
init() {
getPoem()
}
func getPoem() {
let url = URL(string: "https://poetrydb.org/random/1")!
// 2.
URLSession.shared.dataTask(with: url) {(data, response, error) in
do {
if let poemData = data {
// 3.
let decodedData = try JSONDecoder().decode([Poem].self, from: poemData)
DispatchQueue.main.async {
self.poems = decodedData
}
} else {
print("No data")
}
} catch {
print("Error")
}
}.resume()
}
}
測試視圖
import SwiftUI
struct Test: View {
@ObservedObject var fetch = FetchPoem()
@AppStorage("currentPoemtTitle") var currentPoemTitle = ""
@AppStorage("currentPoemAuthor") var currentPoemAuthor = ""
var body: some View {
VStack{
Text(currentPoemTitle)
Button("Fetch next text") {
fetch.getPoem()
}
}.onAppear{
if let poem = fetch.poems.first {
currentPoemTitle = "\(poem.title)"
currentPoemAuthor = "\(poem.author)"
}
}
}
}
struct Test_Previews: PreviewProvider {
static var previews: some View {
Test()
}
}
我錯過了什么? 謝謝。
這里有一些代碼編輯可以幫助您前進。
我添加了 AppStorageKeys 來管理 @AppStorage 鍵,以避免重新鍵入鍵字符串時出錯(即“currentPoemtTitle”)
您的問題詢問如何使用數據更新@AppStorage,簡單的解決方案是在 FetchPoem class 中添加 @AppStorage 變量,並在下載數據后在 FetchPoem class 中設置它們。 這也避免了需要.onAppear function。
使用@ObservedObject 的目的是能夠使您的View 與數據保持同步。 通過添加額外的@AppStorage 層,您使@ObservedObject 變得毫無意義。 在視圖中,我添加了一個 Text() 來直接使用 @ObservedObject 值顯示標題,而不是依賴於 @AppStorage。 我不確定你是否想要這個,但它會完全消除對 @AppStorage 變量的需要。
我還使用 Combine 添加了一個 getPoems2() function,這是 Apple 用於下載異步數據的新框架。 它使代碼更簡單/更高效...... getPoems() 和 getPoems2() 都工作並做同樣的事情:)
代碼:
import Foundation
import SwiftUI
import Combine
struct AppStorageKeys {
static let poemTitle = "current_poem_title"
static let poemAuthor = "current_poem_author"
}
struct Poem: Codable, Hashable {
let title, author: String
let lines: [String]
let linecount: String
}
public class FetchPoem: ObservableObject {
@Published var poems = [Poem]()
@AppStorage(AppStorageKeys.poemTitle) var poemTitle = ""
@AppStorage(AppStorageKeys.poemAuthor) var poemAuthor = ""
init() {
getPoem2()
}
func getPoem() {
let url = URL(string: "https://poetrydb.org/random/1")!
URLSession.shared.dataTask(with: url) {(data, response, error) in
do {
guard let poemData = data else {
print("No data")
return
}
let decodedData = try JSONDecoder().decode([Poem].self, from: poemData)
DispatchQueue.main.async {
self.poems = decodedData
self.updateFirstPoem()
}
} catch {
print("Error")
}
}
.resume()
}
func getPoem2() {
let url = URL(string: "https://poetrydb.org/random/1")!
URLSession.shared.dataTaskPublisher(for: url)
// fetch on background thread
.subscribe(on: DispatchQueue.global(qos: .background))
// recieve response on main thread
.receive(on: DispatchQueue.main)
// ensure there is data
.tryMap { (data, response) in
guard
let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return data
}
// decode JSON data to [Poem]
.decode(type: [Poem].self, decoder: JSONDecoder())
// Handle results
.sink { (result) in
// will return success or failure
print("poetry fetch completion: \(result)")
} receiveValue: { (value) in
// if success, will return [Poem]
// here you can update your view
self.poems = value
self.updateFirstPoem()
}
// After recieving response, the URLSession is no longer needed & we can cancel the publisher
.cancel()
}
func updateFirstPoem() {
if let firstPoem = self.poems.first {
self.poemTitle = firstPoem.title
self.poemAuthor = firstPoem.author
}
}
}
struct Test: View {
@ObservedObject var fetch = FetchPoem()
@AppStorage(AppStorageKeys.poemTitle) var currentPoemTitle = ""
@AppStorage(AppStorageKeys.poemAuthor) var currentPoemAuthor = ""
var body: some View {
VStack(spacing: 10){
Text("App Storage:")
Text(currentPoemTitle)
Text(currentPoemAuthor)
Divider()
Text("Observed Object:")
Text(fetch.poems.first?.title ?? "")
Text(fetch.poems.first?.author ?? "")
Button("Fetch next text") {
fetch.getPoem()
}
}
}
}
struct Test_Previews: PreviewProvider {
static var previews: some View {
Test()
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.