[英]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.