使用核心数据破坏多线程
Posted
技术标签:
【中文标题】使用核心数据破坏多线程【英文标题】:Broken Multithreading With Core Data 【发布时间】:2010-04-01 22:00:12 【问题描述】:这是较早问题的一个更集中的版本,涉及与以前完全不同的主题。
我正在开发一个具有多个线程的 Cocoa Core Data 应用程序。有歌有艺人;每首歌曲都有艺术家关系。有一个委托代码文件,这里没有引用;它或多或少看起来像 XCode 生成的模板。
我使用前一种技术比使用后者好得多,而且任何多线程功能都来自 Core Data 模板。当我以一种方法完成所有 ManagedObjectContext 工作时,我很好。当我将 fetch-or-insert-then-return-object 工作放入单独的方法中时,应用程序会在新方法的 return 语句处暂停(但不会崩溃),如下所示。新方法甚至让自己的 MOC 变得安全,但它没有任何帮助。结果是对 Song 进行了一次添加,并在生成 Artist 后停止。
我没有收到任何错误或异常,但我不知道为什么。我已经调试了wazoo。我的理论是发生的任何错误都在另一个线程中,而我正在观看的错误是永远在等待某事。
我在使用 getArtistObject: 时做错了什么,我该如何解决?谢谢。
- (void)main
NSInteger songCount = 1;
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
[moc setPersistentStoreCoordinator:[[self delegate] persistentStoreCoordinator]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:moc];
/* songDict generated here */
for (id key in songDict)
NSManagedObject *song = [NSEntityDescription insertNewObjectForEntityForName:@"Song" inManagedObjectContext:moc];
[song setValue:[songDictItem objectForKey:@"Name"] forKey:@"title"];
[song setValue:[self getArtistObject:(NSString *) [songDictItem objectForKey:@"Artist"]] forKey:@"artist"];
[songDictItem release];
songCount++;
NSError *error;
if (![moc save:&error])
[NSApp presentError:error];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:moc];
[moc release], moc = nil;
[[self delegate] importDone];
- (NSManagedObject*) getArtistObject:(NSString*)theArtist
NSError *error = nil;
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
[moc setPersistentStoreCoordinator:[[self delegate] persistentStoreCoordinator]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:moc];
NSFetchRequest *fetch = [[[NSFetchRequest alloc] init] autorelease];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Artist" inManagedObjectContext:moc];
[fetch setEntity:entityDescription];
// object to be returned
NSManagedObject *artistObject = [[NSManagedObject alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:moc];
// set predicate (artist name)
NSPredicate *pred = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"name = \"%@\"", theArtist]];
[fetch setPredicate:pred];
NSArray *response = [moc executeFetchRequest:fetch error:&error];
if (error)
[NSApp presentError:error];
if ([response count] == 0) // empty resultset --> no artists with this name
[artistObject setValue:theArtist forKey:@"name"];
NSLog(@"%@ not found. Adding.", theArtist);
return artistObject;
else
return [response objectAtIndex:0];
@end
【问题讨论】:
developer.apple.com/library/content/documentation/Cocoa/… 【参考方案1】:尝试在访问之前锁定托管对象上下文,并在完成后再次解锁:
- (void)main
NSInteger songCount = 1;
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
[moc lock];
[moc setPersistentStoreCoordinator:[[self delegate] persistentStoreCoordinator]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:moc];
[moc unlock];
/* songDict generated here */
for (id key in songDict)
[moc lock];
NSManagedObject *song = [NSEntityDescription insertNewObjectForEntityForName:@"Song" inManagedObjectContext:moc];
[moc unlock];
[song setValue:[songDictItem objectForKey:@"Name"] forKey:@"title"];
[song setValue:[self getArtistObject:(NSString *) [songDictItem objectForKey:@"Artist"]] forKey:@"artist"];
[songDictItem release];
songCount++;
NSError *error;
[moc lock];
if (![moc save:&error])
[NSApp presentError:error];
[moc unlock];
[moc lock];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:moc];
[moc unlock];
[moc release], moc = nil;
[[self delegate] importDone];
- (NSManagedObject*) getArtistObject:(NSString*)theArtist
NSError *error = nil;
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
[moc lock];
[moc setPersistentStoreCoordinator:[[self delegate] persistentStoreCoordinator]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:moc];
[moc unlock];
NSFetchRequest *fetch = [[[NSFetchRequest alloc] init] autorelease];
[moc lock];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Artist" inManagedObjectContext:moc];
[moc unlock];
[fetch setEntity:entityDescription];
// object to be returned
[moc lock];
NSManagedObject *artistObject = [[NSManagedObject alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:moc];
[moc unlock];
// set predicate (artist name)
NSPredicate *pred = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"name = \"%@\"", theArtist]];
[fetch setPredicate:pred];
[moc lock];
NSArray *response = [moc executeFetchRequest:fetch error:&error];
[moc unlock];
if (error)
[NSApp presentError:error];
if ([response count] == 0) // empty resultset --> no artists with this name
[artistObject setValue:theArtist forKey:@"name"];
NSLog(@"%@ not found. Adding.", theArtist);
return artistObject;
else
return [response objectAtIndex:0];
@end
【讨论】:
不行。它仍然点击“返回艺术家对象;”并停止。有趣的是,如果我多次单击触发此操作的按钮,它每次都会对第一首歌曲/艺术家重复相同的操作。有没有办法使用调试器找出它在等待什么(如果有的话)? 我不知道,但希望其他人可以加入。【参考方案2】:你不能锁定 NSManagedObjects!
【讨论】:
以上是关于使用核心数据破坏多线程的主要内容,如果未能解决你的问题,请参考以下文章