我尝试做一件简单的事情:
NSArray * entities = [context executeFetchRequest:inFetchRequest error:&fetchError];
没有什么花哨的东西。但这在iOS 5上会冻结,而在iOS 4上则正常工作。我没有收到任何异常、警告或错误信息;我的应用程序只是简单地冻结了。
请帮助我!我快要崩溃了! ;)
我尝试做一件简单的事情:
NSArray * entities = [context executeFetchRequest:inFetchRequest error:&fetchError];
没有什么花哨的东西。但这在iOS 5上会冻结,而在iOS 4上则正常工作。我没有收到任何异常、警告或错误信息;我的应用程序只是简单地冻结了。
请帮助我!我快要崩溃了! ;)
我不知道您是否也使用了不同的线程。如果是的话,问题在于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循环。如果可能有所帮助,请参考我的代码。但是,苹果的并发文档和他们的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];
...
}
}
希望这能帮到你。
M.
感谢这个页面上提供的提示,教我如何解决从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...");
}
我希望这可能有所帮助...
NSManagedObjectContext
。正如其他人建议的那样,您需要检查线程并确保遵循Core Data的规则。执行获取请求必须发生在创建上下文的线程中。
请记住,这不是线程安全的,尝试从另一个线程执行executeFetchRequest
将导致不可预测的行为。
为了正确执行此操作,请使用
[context performBlock: ^{
NSArray * entities = [context executeFetchRequest:inFetchRequest error:&fetchError];
}];
这将在与上下文相同的线程中执行 executeFetchRequest
,可能是主线程,也可能不是。
使用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
}
NSArray *objects;
@synchronized([self persistentStoreCoordinator]) {
objects = [moc executeFetchRequest:request error:&error];
}