簡體   English   中英

為什么我的@AppStorage 不能在 SwiftUI 上運行?

[英]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()
    }
}

我錯過了什么? 謝謝。

這里有一些代碼編輯可以幫助您前進。

  1. 我添加了 AppStorageKeys 來管理 @AppStorage 鍵,以避免重新鍵入鍵字符串時出錯(即“currentPoemtTitle”)

  2. 您的問題詢問如何使用數據更新@AppStorage,簡單的解決方案是在 FetchPoem class 中添加 @AppStorage 變量,並在下載數據后在 FetchPoem class 中設置它們。 這也避免了需要.onAppear function。

  3. 使用@ObservedObject 的目的是能夠使您的View 與數據保持同步。 通過添加額外的@AppStorage 層,您使@ObservedObject 變得毫無意義。 在視圖中,我添加了一個 Text() 來直接使用 @ObservedObject 值顯示標題,而不是依賴於 @AppStorage。 我不確定你是否想要這個,但它會完全消除對 @AppStorage 變量的需要。

  4. 我還使用 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM