And*_*rei 5 macos exc-bad-access core-data objective-c
在我的应用程序中,我正在删除(或尝试删除)来自两个核心数据存储的所有记录,然后再添加新的记录.它们是2个简单的存储,包含与地址簿中的记录相关的数据(VIContacts包含联系人ID和vcard哈希(整数),VIGroup包含组ID和组名).
要从商店中删除所有联系人,我使用这段代码,在一个名为的方法中-clear::
NSArray *allOldRowsInVIContacts = [[mainContext fetchObjectsForEntityName:[VIContact name]
includePropertyValues:NO
withPredicate:nil] copy];
for (NSManagedObject *obj in allOldRowsInVIContacts) {
@try {
[mainContext deleteObject:obj];
}
@catch (NSException *exception) {
NSLog(@"Exception Triggered: %@", exception.reason);
[NSException raise:exception.reason format:@"thrown on vicontacts."];
}
}
[allOldRowsInVIContacts release];
if (![mainContext save:error]) {
return NO;
}
NSArray *allOldRowsInVIGroups = [[mainContext fetchObjectsForEntityName:[VIGroup name]
includePropertyValues:NO
withPredicate:nil] copy];
NSLog(@"all rows in VIGroups count: %d", [allOldRowsInVIGroups count]);
for (NSManagedObject *obj in allOldRowsInVIGroups) {
@try {
[mainContext deleteObject:obj];
}
@catch (NSException *exception) {
NSLog(@"Exception Triggered: %@", exception.reason);
[NSException raise:exception.reason format:@"thrown on vigroups."];
}
}
[allOldRowsInVIGroups release];
NSLog(@"at the end of -clear: Going to save context.");
/* SAVE */
if (![mainContext save:error]) {
return NO;
}
Run Code Online (Sandbox Code Playgroud)
该应用程序似乎总是围绕VIGroup区域崩溃.
崩溃日志如下:
Crashed Thread: 5 Dispatch queue: com.apple.root.default-priority
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000000
...
Thread 5 Crashed:: Dispatch queue: com.apple.root.default-priority
0 com.apple.CoreFoundation 0x00007fff82532574 __CFBasicHashRehash + 1412
1 com.apple.CoreFoundation 0x00007fff8252b41b __CFBasicHashAddValue + 75
2 com.apple.CoreFoundation 0x00007fff82531f78 CFBasicHashAddValue + 3176
3 com.apple.CoreFoundation 0x00007fff82547899 CFSetAddValue + 121
4 com.apple.CoreData 0x00007fff8520e3dc -[NSManagedObjectContext deleteObject:] + 220
5 com.andrei.AddressBookApp 0x000000010004da9a -[AddressBookFrameworkSyncHelper clear:] + 490
6 com.andrei.AddressBookApp 0x000000010004c8f9 +[AddressBookFrameworkSyncHelper saveSnapshot:] + 105
7 com.andrei.AddressBookApp 0x000000010002d417 -[SLSyncOperation main] + 2631
8 com.apple.Foundation 0x00007fff8b68dbb6 -[__NSOperationInternal start] + 684
Run Code Online (Sandbox Code Playgroud)
其他信息
我用过Instruments来寻找僵尸,但都没有出现.应用程序中存在一些泄漏,但都与Core Data无关.
VIGroup和VIContact之间没有任何关系.它们是独立的独立实体.
奇怪的是,代码似乎永远不会进入@catch,因为控制台Exception triggered: ...在崩溃之前不会接收任何消息.
错误会不时被抛出.该应用程序似乎在Lion上更稳定,但它经常在Mountain Lion和Snow Leopard上崩溃.
谢谢.任何帮助是极大的赞赏.
MOC创建:
我创建了一个'NSOperation'('SLSyncOperation')并将其添加到'NSOperationQueue'.这SLSyncOperation被添加到NSOperationQueue:
[backgroundQueue setMaxConcurrentOperationCount:1];
// has a custom initializer
currentOperation = [[SLSyncOperation alloc] initWithPersistentStoreCoordinator:persistentStoreCoordinator
andDelegate:delegate
forceRemoteSync:forceSync];
[backgroundQueue addOperation:currentOperation];
Run Code Online (Sandbox Code Playgroud)
这是mainSLSyncOperation 的方法(继承自NSOperation):
- (void)main {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
syncProgressTracker = [SLSyncProgressTracker sharedProgressTracker];
syncProgressTracker.currentStatus = SLSyncStatusIdle;
// ... some other setup and sending notifications ...
/* Set up. */
managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
managedObjectContext = [[NSManagedObjectContext alloc] init];
// persistentStoreCoordinator is passed from the app delegate
[managedObjectContext setPersistentStoreCoordinator:persistentStoreCoordinator];
// ... continues with other logic (syncing to a server), and the end of the method is: ...
/* Tear down. */
[managedObjectContext release];
managedObjectModel = nil;
[pool drain];
}
Run Code Online (Sandbox Code Playgroud)
正在使用的MOC:
我在单例类中使用MOC,它是从内部调用的方法调用的SLSyncOperation.我假设在这种情况下,一切都发生在同一个线程中......?我将添加一些测试方法来检查这一点.
MOC在单例类中初始化:
+ (AddressBookFrameworkSyncHelper *)sharedHelper {
if (!_sharedAddressBookHelper) {
_sharedAddressBookHelper = [[AddressBookFrameworkSyncHelper alloc] init];
}
return _sharedAddressBookHelper;
}
- (id)init {
if (self = [super init]) {
mainContext = [(AddressBookAppAppDelegate *)[[NSApplication sharedApplication] delegate] managedObjectContext];
addressBookRef = [ABAddressBook sharedAddressBook];
// disable undo manager - uses less memory
[mainContext setUndoManager:nil];
}
return self;
}
Run Code Online (Sandbox Code Playgroud)
在此之后,我正在使用MOC(mainContext)进行保存,将其传递给其他使用它的方法等.例如
//saving
[sharedABF.mainContext save:error];
// passing it to a Core Data method
VIContact *contactToAdd = [VIContact newOrExistingContactWithID:contactID
inContext:sharedABF.mainContext
error:error];
// that method looks like this
+ (VIContact *)newOrExistingContactWithID:(NSString *)contactID inContext:(NSManagedObjectContext *)context error:(NSError **)error {
VIContact *theContact = [[context fetchObjectsForEntityName:[VIContact name]
includePropertyValues:YES
withPredicate:
@"personID == %@", contactID] lastObject];
if (theContact) {
return [theContact retain];
} else {
// no contact found with that ID, return a new one
VIContact *newContact = [[VIContact alloc] initAndInsertInContext:context];
newContact.personID = contactID;
return newContact;
}
}
// and then fetch all rows in a Core Data entity and remove them
NSArray *allOldRowsInVIContacts = [mainContext fetchObjectsForEntityName:[VIContact name]
includePropertyValues:NO
withPredicate:nil];
for (NSManagedObject *obj in allOldRowsInVIContacts) {
[mainContext deleteObject:obj];
}
if (![mainContext save:error]) {
return NO;
}
Run Code Online (Sandbox Code Playgroud)
该fetchObjectsForEntityName方法取自这里.
我将尝试查看是否使用您提到的方法从不同的线程访问该方法.希望这会有所帮助,并为您提供有关我如何使用MOC的更多信息.
我已经将创建mainContext的线程命名为SLSyncOperationThread.Name set..在应用程序崩溃之前,我放了一个NSLog,它打印出线程的名称.它每次打印出这个帖子的名字.所以它似乎不是一个多线程问题.特别是因为应用程序每次都会在每次到达该点时崩溃.
尝试简单地删除文件而不是对象:
- (void)emptyDatabase{
NSError * error;
// retrieve the store URL
NSURL * storeURL = [[self.managedObjectContext persistentStoreCoordinator] URLForPersistentStore:[[[self.managedObjectContext persistentStoreCoordinator] persistentStores] lastObject]];
// lock the current context
[self.managedObjectContext lock];
[self.managedObjectContext reset];//to drop pending changes
//delete the store from the current managedObjectContext
if ([[self.managedObjectContext persistentStoreCoordinator] removePersistentStore:[[[self.managedObjectContext persistentStoreCoordinator] persistentStores] lastObject] error:&error])
{
// remove the file containing the data
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];
//recreate the store like in the appDelegate method
[[self.managedObjectContext persistentStoreCoordinator] addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];//recreates the persistent store
}
[self.managedObjectContext unlock];
}
Run Code Online (Sandbox Code Playgroud)
首先,你说实体之间没有关系,但是它们之间有什么关系呢?
其次,由于 NULL 指针被取消引用,您会遇到分段错误。
第三,您有多少个 NSManagedObjectContext 对象,以及如何访问它们?
看起来您的clear方法是从 an 内部调用的NSOperationQueue,但它没有在主线程上运行。您不应该同时从多个线程访问单个 MOC。
我最初的赌注(没有进一步的信息)是您正在从多个线程访问 MOC,这是一件非常糟糕的事情。
另外,看起来您正在使用 Matt Gallagher 的单行获取。我认为它返回 a NSSet,而不是NSArray...在这种情况下似乎并不重要,但确保您使用正确的类型总是好的。
编辑
不幸的是,您没有展示如何调用您的clear方法。我敢打赌它就在您用评论替换的内容中:
// ... continues with other logic (syncing to a server), and the end of the method is: ...
Run Code Online (Sandbox Code Playgroud)
无论如何,我确信我的第一个赌注是正确的,并且您正在使用mainContext来自不同线程的 MOC。您的 SLSyncOperation 正在其自己的线程中运行,并使用其自己的 MOC(它创建的 MOC)。然而,在该操作中,它似乎正在调用saveSnapshot哪个调用哪个clear,而哪个调用又正在使用mainContext,而不是创建用于该 中的 MOC NSOperation。
这mainContext是 AppDelegate 拥有的 MOC,用于主线程中的内容。它也在这个“其他”线程中被调用和使用。请参阅您的堆栈跟踪以获取证据。这是核心数据和线程的第一条规则。您不得允许多个线程并发访问同一 MOC。
因此,您正在旋转一个单独的线程来完成一些工作,并创建一个本地 MOC 来完成该工作。一切都很好。但是,您仍然从该线程调用一个明确想要使用的方法mainContext(在本例中saveSnapshot是直接从您的操作的main.
现在,您有多种选择:
将本地生成的 MOC 传递给这些方法,以便它们在正确的 MOC 上运行。也许您打算拍摄该 MOC 的快照?
如果您确实打算让这些方法在 MOC 上运行mainContext,那么您需要确保它们在主线程中执行。我不喜欢perform选择器,更喜欢直接 GCD。
dispatch_async(dispatch_get_main_queue(), ^{
// Now you can call the saveSnapshot and other stuff that must use
// mainContext since stuff in this block will execute on the main thread.
});
Run Code Online (Sandbox Code Playgroud)
如果您正在使用主 MOC,并且有任何其他线程,我强烈建议您不要对主 MOC 使用限制并发。相反,我建议采用这种替代方案:
managedObjectContext = [[NSManagedObjectContext alloc]
initWithConcurrencyType:NSMainQueueCurrencyType];
Run Code Online (Sandbox Code Playgroud)
现在,该 MOC 可以像另一个 MOC 一样使用,无需更改代码(换句话说,在主线程上使用时,它仍然会像限制 MOC 一样正常工作)。然而,它也可以更合适地从其他线程使用:
[managedObjectContext performBlock:^{
// Do anything with this MOC because its protected, and
// running on the right thread.
}];
Run Code Online (Sandbox Code Playgroud)
如果有必要,你可以调用performBlockAndWaitwhich是可重入的(dispatch_sync是不可重入的——它会导致死锁)。您仍然必须小心任何操作,以sync避免从同一个线程递归调用但不会出现死锁。deadly embraceperformBlockAndWait
| 归档时间: |
|
| 查看次数: |
3512 次 |
| 最近记录: |