【发布时间】:2022-10-08 14:56:10
【问题描述】:
我正在修改我的 coreData 方法以使用 async 和 await 目前,但在理解 Swift 中的这些队列时仍然遇到问题, 也许你们可以在这里帮助我..
问题是,我想在函数“newUpdateMethod()”中处理每个步骤后收集反馈(logComment) 对我有用的唯一方法是将:“@MainActor”放在函数前面
据我了解,这意味着我强制该函数在主队列上运行,而不是在异步作业将运行的后台队列上运行。 由于那个主队列,我能够沿途填充变量“logComment”并将其返回给调用它的 VC.. 但我不确定100,如果这种方式真的有必要,那么必须有另一种方式来实现这一点...... 我试图将 logComment 语句放在 DispatchQueue.main.sync 块中以与主队列对话,但仍然: “并发执行代码中捕获的 var 'logComment' 的突变”
我的 coreData 方法
- json 获取方法
import UIKit import CoreData class CoreDataInteraction { //(...) func getRemoteData() async throws -> [RemoteData] { var remoteData = [RemoteData]() do { let url = URL(string: "***")! let urlRequest = URLRequest(url: url) let (data, _) = try await URLSession.shared.data(for: urlRequest) remoteData = try JSONDecoder().decode([RemoteData].self, from: data) }catch{ let url = Bundle.main.url(forResource: "remoteData", withExtension: "json") // use local data instead let urlRequest = URLRequest(url: url!) let (data, _) = try await URLSession.shared.data(for: urlRequest) remoteData = try JSONDecoder().decode([RemoteWire].self, from: data) DispatchQueue.main.sync { Logging.insertError(message: error.localizedDescription, location: "get json data") } } return remoteData }- 更新方法
@MainActor // really necessary ? func newUpdateMethod(completion: @escaping (String?) -> Void){ var logComment:String = "" let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext let request = RemoteData.fetchRequest() as NSFetchRequest<RemoteData> Task { do { // Step 1 let jsonData = try await getRemoteData() logComment = logComment + "\n Line 1" // Step 2 var existingData = try context.fetch(request); logComment = logComment + "\n Line 2" // Step 3 comparison.. // ... logComment = logComment + "\n Line 3" // Step 4 ... // continue . . . } completion(logComment) } } }这是调用该更新方法接收反馈并将其放入 UI 的 VC 函数
class SettingsVC: UIViewController { //(...) @IBAction func updateButtonPressed(_ sender: Any) { //MARK: NEW Update processing self.LoadingStart() myCoreData.newUpdateMethod() {(success) in self.LoadingStop() self.updateTextField.font = UIFont.systemFont(ofSize: 12.0) self.updateTextField.text = success self.updateButton.isEnabled = false } } }我发现除了@MAinActor 之外没有其他方法可以让这件事发挥作用.. 必须有一种方法可以从任务/执行后台队列中获取变量的值,否则在我的理解中它是非常没用的 显然我在这里的理解中遗漏了一些东西:/
【问题讨论】:
-
不相关,但我建议不要在从 bundle 读取数据时使用
URLSession。从本地文件系统读取时只需使用Data(contentsOf:)。 -
我还想知道为什么您仍在使用
newUpdateMethod中的完成处理程序代码。 async-await 的整个想法是它使该模式变得不必要。 -
如果您还没有看过,我可能会建议您查看 WWDC 2021 Bring Core Data concurrency to Swift and SwiftUI。
-
thx @Rob 我刚刚看过那个视频,context.perform 对我来说不是一个选项,因为我的应用程序的目标 iOS 版本是 14 ..我有点理解这个话题,但我仍然遇到问题,采用这种新语法我自己的项目:(
标签: swift xcode asynchronous async-await