我尝试做以下简单的事情:
NSArray * entities = [context executeFetchRequest:inFetchRequest error:&fetchError];
没什么特别的。但这在iOS 5中冻结,它在iOS 4中运行良好。我没有异常,警告或错误;我的应用只是冻结。
请帮帮我!我快死了! ;)
答案 0 :(得分:19)
我不知道你是否也使用不同的Thread。如果是,则问题来自NSManagedObjects本身不是线程安全的事实。在主线程上创建ManagedContext并在另一个线程上使用它会冻结线程。
也许这篇文章可以帮到你: http://www.cimgf.com/2011/05/04/core-data-and-threads-without-the-headache/
Apple有一个演示应用程序,用于在多个线程(通常是主线程和后台线程)上处理Coredata:http://developer.apple.com/library/ios/#samplecode/TopSongs/Introduction/Intro.html
我为解决这个问题所做的是:
使用NSQueueOperation有几种解决方案。对于我的情况,我正在使用while循环。这是我的代码,如果它可以帮助你。但是,关于并发性的Apple文档及其Top Songs示例应用程序是很好的起点。
在应用程序委托中:
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.cdw = [[CoreDataWrapper alloc] initWithPersistentStoreCoordinator:[self persistentStoreCoordinator] andDelegate:self];
remoteSync = [RemoteSync sharedInstance];
...
[self.window addSubview:navCtrl.view];
[viewController release];
[self.window makeKeyAndVisible];
return YES;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator == nil) {
NSURL *storeUrl = [NSURL fileURLWithPath:self.persistentStorePath];
NSLog(@"Core Data store path = \"%@\"", [storeUrl path]);
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[NSManagedObjectModel mergedModelFromBundles:nil]];
NSError *error = nil;
NSPersistentStore *persistentStore = [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error];
NSAssert3(persistentStore != nil, @"Unhandled error adding persistent store in %s at line %d: %@", __FUNCTION__, __LINE__, [error localizedDescription]);
}
return persistentStoreCoordinator;
}
-(NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext == nil) {
managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
}
return managedObjectContext;
}
-(NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator == nil) {
NSURL *storeUrl = [NSURL fileURLWithPath:self.persistentStorePath];
NSLog(@"Core Data store path = \"%@\"", [storeUrl path]);
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[NSManagedObjectModel mergedModelFromBundles:nil]];
NSError *error = nil;
NSPersistentStore *persistentStore = [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error];
NSAssert3(persistentStore != nil, @"Unhandled error adding persistent store in %s at line %d: %@", __FUNCTION__, __LINE__, [error localizedDescription]);
}
return persistentStoreCoordinator;
}
-(NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext == nil) {
managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
}
return managedObjectContext;
}
-(NSString *)persistentStorePath {
if (persistentStorePath == nil) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths lastObject];
persistentStorePath = [[documentsDirectory stringByAppendingPathComponent:@"mgobase.sqlite"] retain];
}
return persistentStorePath;
}
-(void)importerDidSave:(NSNotification *)saveNotification {
if ([NSThread isMainThread]) {
[self.managedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification];
} else {
[self performSelectorOnMainThread:@selector(importerDidSave:) withObject:saveNotification waitUntilDone:NO];
}
}
在运行后台线程的对象中:
monitor = [[NSThread alloc] initWithTarget:self selector:@selector(keepMonitoring) object:nil];
-(void)keepMonitoring{
while(![[NSThread currentThread] isCancelled]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
AppDelegate * appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
//creating the cdw here will create also a new managedContext on this particular thread
cdwBackground = [[CoreDataWrapper alloc] initWithPersistentStoreCoordinator:appDelegate.persistentStoreCoordinator andDelegate:appDelegate];
...
}
}
希望得到这个帮助,
微米。
答案 1 :(得分:11)
感谢本页提供的有关如何解决从iOS4升级时出现的冻结问题的提示。自从我开始在iOS上编程以来,它一直是我发现的最烦人的问题。
我已经找到了一个快速解决方案,用于从其他线程调用上下文的几个。
我只使用 performSelectorOnMainThread :
[self performSelectorOnMainThread:@selector(stateChangeOnMainThread:) withObject: [NSDictionary dictionaryWithObjectsAndKeys:state, @"state", nil] waitUntilDone:YES];
要检测从另一个线程调用上下文的位置,您可以在NSLog上为您调用上下文的函数放置一个断点,如下面的代码段所示,只需使用 performSelectorOnMainThread 它们。
if(![NSThread isMainThread]){
NSLog(@"Not the main thread...");
}
我希望这可能会有所帮助......
答案 2 :(得分:6)
我有同样的问题。如果你在调试器下运行,当应用程序“挂起”时停止应用程序(使用调试器上的“暂停”按钮。如果你在executeFetchRequest行,那么检查上下文变量。如果它有一个ivar _objectStoreLockCount及其大于1,然后等待关联商店的锁定。
您正在相关商店创建竞争条件。
答案 3 :(得分:4)
这听起来像是尝试从创建它的线程/队列之外的线程/队列中访问NSManagedObjectContext
。正如其他人建议您需要查看线程并确保遵循Core Data的规则。
答案 4 :(得分:3)
执行获取请求必须从创建上下文的线程发生。
请记住,它不是线程安全的,尝试从另一个线程executeFetchRequest
将导致不可预测的行为。
为了正确执行此操作,请使用
[context performBlock: ^{
NSArray * entities = [context executeFetchRequest:inFetchRequest error:&fetchError];
}];
这将executeFetchRequest
在与上下文相同的线程中,它可能是也可能不是主线程。
答案 5 :(得分:0)
在我的情况下,应用程序会在“executeFetchRequest”之前冻结,而不会发出任何警告。解决方案是将所有数据库操作包装在@synchronized(persistentStore)中。 例如:
NSArray *objects;
@synchronized([self persistentStoreCoordinator]) {
objects = [moc executeFetchRequest:request error:&error];
}
答案 6 :(得分:0)
使用fetchrequest删除所有对象对我不起作用,sqlite看起来已损坏。我发现的唯一方法是
//Erase the persistent store from coordinator and also file manager.
NSPersistentStore *store = [self.persistentStoreCoordinator.persistentStores lastObject];
NSError *error = nil;
NSURL *storeURL = store.URL;
[self.persistentStoreCoordinator removePersistentStore:store error:&error];
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];
//Make new persistent store for future saves (Taken From Above Answer)
if (![self.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// do something with the error
}