ios - 当应用程序在后台 Swift 中时,performBackgroundTask 不保存
问题描述
我正在使用 Xcode 9 和 Swift 4。当应用程序在前台时,我开始下载多个 JSON 文件。然后应用程序解析这些文件并将它们保存到 CoreData。当应用程序在前台时,这很有效。但是,如果应用程序在后台,文件仍然可以正确下载,但数据不会被解析并保存到 CoreData。只有当用户返回前台时,数据的解析和保存才会继续。
我打开了后台模式 - 后台获取和远程通知。
我有大约 10 个函数,类似于下面的函数,它同时处理 JSON 文件:
func populateStuff(json: JSONDictionary) -> Void {
let results = json["result"] as! JSONDictionary
let stuffData = results["Stuff"] as! [JSONDictionary]
let persistentContainer = getPersistentContainer()
persistentContainer.performBackgroundTask { (context) in
for stuff in stuffData {
let newStuff = Stuff(context: context)
newStuff.stuffCode = stuff["Code"] as? String
newStuff.stuffDescription = stuff["Description"] as? String
do {
try context.save()
} catch {
fatalError("Failure to save context: \(error)")
}
}
}
}
func getPersistentContainer() -> NSPersistentContainer {
let persistentContainer = NSPersistentContainer(name: "MyProjectName")
persistentContainer.loadPersistentStores { (_, error) in
if let error = error {
fatalError("Failed to load core data stack: \(error.localizedDescription)")
}
}
persistentContainer.viewContext.automaticallyMergesChangesFromParent = true
persistentContainer.viewContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
return persistentContainer
}
谁能告诉我为什么会发生这种情况以及如何克服这种情况?
TIA
解决方案
使用beginBackgroundTaskWithName:expirationHandler:
方法:
func populateStuff(json: JSONDictionary) -> Void {
// Perform the task on a background queue.
DispatchQueue.global().async {
// Request the task assertion and save the ID.
self.backgroundTaskID = UIApplication.shared.beginBackgroundTask (withName: "Finish Network Tasks") {
// End the task if time expires.
UIApplication.shared.endBackgroundTask(self.backgroundTaskID!)
self.backgroundTaskID = UIBackgroundTaskInvalid
}
// Parse the json files
let results = json["result"] as! JSONDictionary
let stuffData = results["Stuff"] as! [JSONDictionary]
let persistentContainer = getPersistentContainer()
persistentContainer.performBackgroundTask { (context) in
for stuff in stuffData {
let newStuff = Stuff(context: context)
newStuff.stuffCode = stuff["Code"] as? String
newStuff.stuffDescription = stuff["Description"] as? String
do {
try context.save()
} catch {
fatalError("Failure to save context: \(error)")
}
}
}
// End the task assertion.
UIApplication.shared.endBackgroundTask(self.backgroundTaskID!)
self.backgroundTaskID = UIBackgroundTaskInvalid
}
调用此方法可为您提供额外的时间来执行重要任务。endBackgroundTask:
请注意在任务完成后立即使用方法。它让系统知道你已经完成了。如果您没有及时结束您的任务,系统将终止您的应用程序。
推荐阅读
- wordpress - WPBakery Wordpress DOM元素的重复
- c# - 错误无法将 DBNULL 对象转换为其他 C# Datagridview 类型
- java - 当玩家转动(旋转)时,KeyPressed 方法不会更新
- bootstrap-4 - 带有灯箱弹出窗口的引导轮播,包括滑块
- oracle-apex - 在 Oracle Apex 应用程序中启动触发器的问题
- ajax - 使用 AJAX 进行 GET 的 Razor Pages PageModel 绑定
- python - 我需要在图表上绘制很多 X,但是有没有办法不必直接指定颜色?
- vaadin - 如何向 Vaadin 组件添加悬停文本?
- amazon-web-services - 亚马逊销售合作伙伴 API“活动密钥过多”
- visual-c++ - 我必须链接什么以避免 _aligned_alloc(MSVC 命令行)上的链接器错误?