我有一个使用Core Data的应用程序,具有以下相当标准的托管对象上下文层次结构:
Persistent Store Coordinator
? Save Context (Private Queue Concurrency Type)
? Main Context (Main Queue Concurrency Type)
? Private Context (Private Queue Concurrency Type)
Run Code Online (Sandbox Code Playgroud)
所有托管对象上下文的合并策略都设置为 NSMergeByPropertyObjectTrumpMergePolicy
我观察NSManagedObjectContextDidSaveNotification当保存私有上下文并将更改合并到主上下文时,将调用以下函数:
func contextDidSaveNotificationHandler(notification: NSNotification) {
if let savedContext = notification.object as? NSManagedObjectContext {
if savedContext == privateObjectContext {
mainObjectContext.performBlock({
if let updatedObjects = notification.userInfo![NSUpdatedObjectsKey] as? Set<NSManagedObject> {
//
// fire faults on the updated objects
//
for obj in updatedObjects {
mainObjectContext.objectWithID(obj.objectID).willAccessValueForKey(nil)
}
}
mainObjectContext.mergeChangesFromContextDidSaveNotification(notification)
})
}
}
}
Run Code Online (Sandbox Code Playgroud)
这大部分时间都在工作,但有时我发现私有上下文中对现有对象的更改未合并到主上下文中.我无法弄清楚为什么 …
我的应用程序中发生了一次崩溃,很少发生(可能每30次运行一次).错误代码包含一个奇怪的选择器名称_nilOutReservedCurrentEventSnapshot__,我根本找不到任何文档.这是来自我的控制台的提要:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFType _nilOutReservedCurrentEventSnapshot__]: unrecognized selector sent to instance 0x157b51e0'
*** First throw call stack:
(0x2358810b 0x22d2ee17 0x2358d925 0x2358b559 0x234bbc08 0x24cbf445 0x24ca4d99 0x249bec 0x245c90 0x19b68c 0x24a5c97 0x24b05ab 0x24a8ef9 0x24b1a8d 0x24b18e7 0x232bfb29 0x232bf718)
libc++abi.dylib: terminating with uncaught exception of type NSException
Run Code Online (Sandbox Code Playgroud)
如果有人能够阐明这句话_nilOutReservedCurrentEventSnapshot__`的含义,那将对我有很大的帮助.崩溃位置的屏幕截图如下:
好的,所以我遇到一个令人沮丧的问题,我希望得到一些帮助或建议.基本上我有一个我正在开发的应用程序,Core Data用于存储众多用户属性.我在开发过程中几个月来一直在做的是,managedObjectContext每当用户从活动状态转换到后台时,我都会保存.我使用了一些后台获取请求,所以我被告知要专门使用applicationDidEnterBackgroundin AppDelegate而不是applicationWillTerminate函数.基本上我正在做类似的事情:
func applicationDidEnterBackground(application: UIApplication) {
if !userSaved {
saveUserDataLocally()
}
}
func saveUserDataLocally() {
// Handle all the data, store it properly in managedObjectContext
// .........
// .......
do {
try managedObjectContext.save()
print("Success on save")
} catch let error {
print("Error saving user \(error)")
}
}
Run Code Online (Sandbox Code Playgroud)
现在,当我通过xCode在我的iPhone上测试应用程序时,这已经好几个月了.每当我将应用程序推入后台时它仍然可以正常工作,并等待几秒钟以保存managedObjectContext到完成(如果存储了大量数据,有时可能需要3-4秒).只有当我通过xCode测试应用程序时才会出现问题.因此,如果我在手机上安装了应用程序,并且只是在乘坐公共汽车去学校时尝试测试,我会遇到问题.当我将应用程序推入后台模式时,它只会导致崩溃,然后立即点击主屏幕上的应用程序图标再次启动它(好像我不小心点击了主页按钮将其推入后台).如果我没有通过xCode测试并尝试强制退出应用程序,情况也是如此.在这种情况下,它不会崩溃,因为应用程序没有运行,但它永远不会完成保存.
我已经不知疲倦地尝试重新解决这个问题,同时让我的手机插入我的电脑并通过xCode进行测试,这样我就可以安装断点并找到问题的根源.通过xCode进行测试时,此问题始终存在.当我测试它时,我可以将应用程序推送到后台,然后半秒后将其重新启动,不仅原始保存请求完成,而且不会导致崩溃.此外,我可以强制退出应用程序,同时通过xCode运行它,它将允许保存完成,然后应用程序将终止.
我确信你可以想象,这是非常令人沮丧的,因为如果我在使用xCode提供的调试工具时无法重新创建问题,我很难找到错误的来源.只是明哲保身,我确信无数次,没有什么是被称为在AppDelegate的applicationWillEnterForeground或applicationDidBecomeActive方法.我完全迷失了.在我看来,通过将应用程序推回到前台,同时处于保存状态managedObjectContext,它会变得混乱和崩溃...但是当我在使用xCode测试我的设备上的应用程序时,为什么不会发生这种情况?
任何人都可以帮我吗?我可能在几个小时内没有留下任何头发!;-)
||| 更新06/03 |||
所以在一些评论者的帮助下,我能够发现问题的一部分是由于CoreData请求堵塞主线程,然后导致应用程序停止响应.我不确定这是我具体问题的确切解决方案,但绝对有助于完全识别问题.转换到后台时我试图完成所有保存的原因之一是因为我在主线程上执行了所有保存,当我在应用程序使用期间执行保存时,会导致延迟或陷入困境主线程.我一直在尝试在后台线程上执行保存执行,这非常有帮助.这样,我可以在应用程序的其他部分运行时将我的用户数据保存在后台,并且它不会阻塞主线程.这有助于使我在转换到后台时甚至不需要保存,因此崩溃不会再发生了.
我CoreData在mainthread.com上找到了一个名为Justin …
问题:更新并快速保存表格之间的关系,其中包含大量数据或其中一个表已经保存.
我有五个表TvGenres,TvSubgenre,TvProgram,Channels,TvSchedules与它们之间的关系,如下图所示
现在的问题是所有的数据下载都是根据以前的数据顺序发生的,而且与SQLite不同,我需要设置它们之间的关系,为此我必须一次又一次地搜索表并设置它们之间的关系,这是很费时的,所以如何我能更快地做到这一点吗?
我使用2种不同的方法来解决,但两种方法都没有按预期工作
首先让我告诉我,下载是如何工作的
首先,我根据用户语言获取所有频道详细信息从频道,我获取下一周的所有时间表(这是大量数据(大约30k +))从调度数据,我获取所有程序数据(这也是很多数据的 )
方法1,
下载所有数据并创建它们的对象列表,然后在所有下载完成后立即存储它们但仍然设置它们之间的关系需要时间和最糟糕的事情现在循环发生两次首先我必须循环创建所有类列表然后循环再次存储在表视图中仍然没有解决关系耗时的问题.
方法2
像下载频道一样逐个下载存储它们,然后下载时间表存储它们然后下载程序然后将它们存储在核心数据中这一切都可以,但现在频道与时间表有关系,时间表与程序有关系,并设置关系,而我我存储时间表我也获取与该时间表相关的通道,然后设置关系,对于程序和时间表是相同的,下面花费时间的是代码,所以如何解决这个问题或者我应该如何下载和存储以便它变得如此快可能.
仅用于存储计划的代码
func saveScheduleDataToCoreData(withScheduleList scheduleList: [[String : Any]], completionBlock: @escaping (_ programIds: [String]?) -> Void) {
let start = DispatchTime.now()
let context = coreDataStack.managedObjectContext
var progIds = [String]()
context.performAndWait {
var scheduleTable: TvSchedule!
for (index,response) in scheduleList.enumerated() {
let schedule: TvScheduleInformation = TvScheduleInformation(json: response )
scheduleTable = TvSchedule(context: context)
scheduleTable.channelId = schedule.channelId
scheduleTable.programId = schedule.programId
scheduleTable.startTime = schedule.startTime
scheduleTable.endTime = schedule.endTime
scheduleTable.day = schedule.day
scheduleTable.languageId = schedule.languageId
scheduleTable.isReminderSet = …Run Code Online (Sandbox Code Playgroud) 我想开始学习使用NSAsynchronousFetchRequest参考https://www.marcosantadev.com/coredata_crud_concurrency_swift_2/
我有最简单的用例NSAsynchronousFetchRequest
// Call from UI main thread
func X() {
let fetchRequest = NSFetchRequest<NSPlainNote>(entityName: "NSPlainNote")
let asynchronousFetchRequest = NSAsynchronousFetchRequest(fetchRequest: fetchRequest) { asynchronousFetchResult in
guard let result = asynchronousFetchResult.finalResult as? [NSPlainNote] else { return }
}
let coreDataStack = CoreDataStack.INSTANCE
// backgroundContext created via persistentContainer.newBackgroundContext()
let backgroundContext = coreDataStack.backgroundContext
backgroundContext.perform {
do {
try backgroundContext.execute(asynchronousFetchRequest)
} catch let error {
backgroundContext.rollback()
error_log(error)
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是,运行上面的代码会出现以下错误
CoreData`+[NSManagedObjectContext Multithreading_Violation_AllThatIsLeftToUsIsHonor ]:
如果我修改代码NSFetchRequest直接使用.
// Call …Run Code Online (Sandbox Code Playgroud)