我刚刚“解决”了似乎是死锁或同步问题:
[NSThread sleepForTimeInterval:0.1];
在将来自IPOD库的MPMediaItem(音乐/图像)属性引用附加到对象实例的应用程序中,这些对象通过CoreData进行反向存储。我的兴趣是要准确了解发生了什么,以及在这种情况下最佳做法是什么。这是:
每次复制此内容的方法如下:
用户创建一个新项目。
doc = [[UIManagedDocument alloc] initWithFileURL:docURL];
if (![[NSFileManager defaultManager] fileExistsAtPath:[docURL path]]) {
[doc saveToURL:docURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
if (success) {
completionBlock(doc);
}
else {
DLog(@"Failed document creation: %@", doc.localizedName);
}
}];
稍后,managedObjectContext用于关联对象实例并为CoreData模型提供水合作用
TheProject *theProject = [TheProject projectWithInfo:theProjectInfo
inManagedObjectContext:doc.managedObjectContext];
用户稍后创建“CustomAction”对象,向其添加“ChElement”并将“MusicElement”与ChElement相关联。 (这些是CoreData模型对象的假名)。 MusicElement通过IPOD库添加。
#define PLAYER [MPMusicPlayerController iPodMusicPlayer]
用户保存此项目,然后切换到已创建一个CustomAction对象的现有项目,其中包含ChElement和MusicElement。
用户从tableView中选择该ChElement并导航到detailView。 当导航离开ChElementTVC(类似于Apple文档中的CoreData TableViewController类的子类)时,这是必需的:
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
self.fetchedResultsController.delegate = nil;
}
在详细视图中,用户更改ChElement对象的属性并保存项目。 detailView调用其委托(ChElementTVC)来进行保存。保存是保存NSManagedObject的UIManagedDocument实例。
#define SAVEDOC(__DOC__) [ProjectDocumentHelper saveProjectDocument:__DOC__]
// Delegate
- (void)chAddElementDetailViewController:(ChDetailViewController *)sender didPressSaveButton:(NSString *)message
{
SAVEDOC(THE_CURRENT_PROJECT_DOCUMENT);
[self.navigationController popViewControllerAnimated:YES];
}
// Helper Class
+ (void)saveProjectDocument:(UIManagedDocument *)targetDocument
{
NSManagedObjectContext *moc = targetDocument.managedObjectContext;
[moc performBlockAndWait:^{
DLog(@" Process Pending Changes before saving : %@, Context = %@", targetDocument.description, moc);
[moc processPendingChanges];
[targetDocument saveToURL:targetDocument.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:NULL];
}];
}
由于委托(ChElementTVC)从导航堆栈中弹出detailView, 调用viewWillAppear,并恢复fetchedResultsController.delegate。
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (!self.fetchedResultsController.delegate) {
DLog(@"Sleep Now %@", self);
//http://mobiledevelopertips.com/core-services/sleep-pause-or-block-a-thread.html
[NSThread sleepForTimeInterval:0.1];
DLog(@"Wake up %@", self);
[self fetchedResultsControllerWithPredicate:_savedPredicate]; // App Hangs Here ... This is sending messages to CoreData objects.
[self.tableView reloadData];
}
没有[NSThread sleepForTimeInterval:0.1];
应用程序挂起。当我通过Xcode发送SIGINT时,我得到调试器并显示以下内容:
(lldb)bt
* thread #1: tid = 0x1c03, 0x30e06054 libsystem_kernel.dylib semaphore_wait_trap + 8, stop reason = signal SIGINT
frame #0: 0x30e06054 libsystem_kernel.dylib semaphore_wait_trap + 8
frame #1: 0x32c614f4 libdispatch.dylib _dispatch_thread_semaphore_wait$VARIANT$mp + 12
frame #2: 0x32c5f6a4 libdispatch.dylib _dispatch_barrier_sync_f_slow + 92
frame #3: 0x32c5f61e libdispatch.dylib dispatch_barrier_sync_f$VARIANT$mp + 22
frame #4: 0x32c5f266 libdispatch.dylib dispatch_sync_f$VARIANT$mp + 18
frame #5: 0x35860564 CoreData _perform + 160
(lldb)帧选择5
frame #5: 0x35860564 CoreData _perform + 160
CoreData _perform + 160:
-> 0x35860564: add sp, #12
0x35860566: pop {r4, r5, r7, pc}
CoreData -[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]:
0x35860568: push {r4, r5, r6, r7, lr}
0x3586056a: add r7, sp, #12
(lldb)反汇编-f
CoreData _perform:
0x358604c4: push {r4, r5, r7, lr}
... snipped ...
0x35860560: blx 0x35938bf4 ; symbol stub for: dispatch_sync_f
-> 0x35860564: add sp, #12
0x35860566: pop {r4, r5, r7, pc}
另一种解决方法是可行的。在-[ChElementTVC viewDidAppear:]
中对fetchedResultsController.delegate恢复进行编码也会有效地延迟主队列上的此设置。
另一种解决方法是在项目保存完成后在完成块中执行nav pop:
#define SAVEDOCWITHCOMPLETION(__DOC__,__COMPLETION_BLOCK__)[ProjectDocumentHelper saveProjectDocument:__DOC__ completionHandler:__COMPLETION_BLOCK__]
void (^completionBlock)(BOOL) = ^(BOOL success) {
[self.navigationController popViewControllerAnimated:YES];
};
SAVEDOCWITHCOMPLETION(THE_CURRENT_PROJECT_DOCUMENT, completionBlock);
我认为保存操作在后台与主队列上的委托恢复同时运行,但我不知道如何检查/证明/反驳该理论。
因此,有人可以解释发生了什么,在这种情况下最佳做法是什么?此外,赞赏研究参考。
答案 0 :(得分:1)
我最终实现了第三种方法,即使用完成块保存文档以序列化与CoreData存储交互的事务。