簡體   English   中英

如何用SwiftUI按鈕做異步動作

[英]How to do asynchronous action with SwiftUI button

我想單擊 SwiftUI 中的一個按鈕,這將觸發 JSON 編碼操作。 這個動作很耗時,因此我需要它是異步的。 我已經嘗試了兩種解決方案,但它們不起作用。 一個主要問題是如何創建 json 編碼的異步版本?

解決方案 1)

public func encodeJSON<T>(_ value: T, encoder: JSONEncoder, completionHandler: @escaping (Data?, Error?) -> Void) where T: Encodable {
        DispatchQueue.global().async {
            do {
                let data = try encoder.encode(value)
                DispatchQueue.main.async {
                    completionHandler(data, nil)
                    print("finish encode json")
                }
            } catch {
                DispatchQueue.main.async {
                    completionHandler(nil, error)
                    print("fail encode json")
                }
            }
        }
    }
    
    public func encodeJSON<T>(_ value: T, encoder: JSONEncoder) async throws -> Data where T: Encodable {
        
        try await withUnsafeThrowingContinuation { continuation in
            encodeJSON(value, encoder: encoder) { data, error in
                if let error = error {
                    continuation.resume(throwing: error)
                } else if let data = data {
                    continuation.resume(returning: data)
                } else {
                    fatalError()
                }
            }
        }
    }

我在 SwiftUI 主體中調用 function:

Button {
                
                let localDate = dailyUploadRecord.date!
                let impactMed = UIImpactFeedbackGenerator(style: .medium)
                impactMed.impactOccurred()
 
                
               
                guard let file = UploadFileManager.shared.fetchedResults else { return }
                
                let encoder = JSONEncoder()
                encoder.dateEncodingStrategy = .millisecondsSince1970
                
                Task {
                    isEncoding = true
                    let result = try await uploadManager.encodeJSON(file, encoder: encoder)
                    print(result)
                    isEncoding = false
                }

            } label: {
                Text(“TEST")
                    .overlay {
                        if isEncoding {
                            ProgressView()
                        }
                    }
            }
            .disabled(isEncoding)
            .buttonStyle(.bordered)

但是,它給了我運行時錯誤: Thread 6: EXC_BREAKPOINT (code=1, subcode=0x1b338b088)

然后,我嘗試了第二種解決方案:

public func encodeJSON<T>(_ value: T, encoder: JSONEncoder) async throws -> Data where T: Encodable {
        return try encoder.encode(value)
    }
Button {
                
            let localDate = dailyUploadRecord.date!
            let impactMed = UIImpactFeedbackGenerator(style: .medium)
            impactMed.impactOccurred()
                
            guard let file = UploadFileManager.shared.fetchedResults else { return }
                
            let encoder = JSONEncoder()
            encoder.dateEncodingStrategy = .millisecondsSince1970
                
            Task {
                isEncoding = true
                let result = try await encodeJSON(file, encoder: encoder)
                print(result)
                isEncoding = false
            }

        } label: {
            Text(“TEST")
                .overlay {
                    if isEncoding {
                        ProgressView()
                    }
                }
        }
        .disabled(isEncoding)
        .buttonStyle(.bordered)

但是,ui 被凍結,當 encodeJSON 完成后,它恢復正常,我可以與之交互。

我的問題是:如何創建異步版本的JSONEncoder().encode(value: Data) 並在SwiftUI 的Button 中調用它,而不阻塞主線程(使UI 凍結)? 歡迎任何建議!

我嘗試了兩種解決方案。 一種是從 DispatchQueue.global().async {} 創建一個異步版本並轉換它。 另一種是直接將 JSONEncoder().encode(value: Data) 包裝在異步 function 中。但是,這兩種解決方案均無效。

我希望點擊按鈕,相關編碼 function 可以異步執行。

第二種方式是正確的。 問題很可能是編碼器拋出異常,當數據中的某些內容無法編碼時會發生這種異常。 這意味着未到達isEncoding = false行並且 UI 卡在編碼 state 中。像這樣修復它:

Task {
       isEncoding = true
       do {
           let result = try await encodeJSON(file, encoder: encoder)
            print(result)
        }
        catch {
           print(error.localizedDescription)
        }
        isEncoding = false
     }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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