Note that there are some explanatory texts on larger screens.

plurals
  1. POEXC_BAD_ACCESS with NSOPERATION and ARC
    text
    copied!<p>I have an application that works fine in an older project (that doesn't use ARC and was written against in Xcode 4.0 with iOS 4.2.</p> <p>I am trying to port this application over to use ARC and storyboard with Xcode 4.2 and iOS 5.</p> <p>I have got everything ported over and fixed all the error caused by retaining, releasing, deallocing, etc. The project builds fine now. I also rebuilt my Core Data model in the new project and rebuild my model subclasses.</p> <p>Where the error happens is when I try to parse an XML file in a background thread. The file is local to the project. I NSLog the initializer for each NSOperation class that does the parsing (there are four of them). I am getting to that point of the application, the error occurs when I add the operations to the queue.</p> <p>Here is my code in the AppDelegate that starts the Operations:</p> <pre><code>#import "AppDelegate.h" #import "ACHPhonebook.h" @implementation AppDelegate @synthesize window = _window; @synthesize managedObjectContext = __managedObjectContext; @synthesize managedObjectModel = __managedObjectModel; @synthesize persistentStoreCoordinator = __persistentStoreCoordinator; @synthesize parseQueue; @synthesize parseOpAD, parseOpEK, parseOpLR, parseOpSZ; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSFetchRequest *request = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"ACHPhonebook" inManagedObjectContext:self.managedObjectContext]; [request setEntity:entity]; NSError *error = nil; NSUInteger count = [self.managedObjectContext countForFetchRequest:request error:&amp;error]; NSLog(@"total CD count = %d", count); if( getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled") ) { NSLog(@"NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled enabled!"); } if (count == 0) { // Purge the DB [ACHPhonebook purgePhoneBook:self.managedObjectContext]; // NSLog(@"Just purged the phonebook"); // Set up the NSOperation Queue for the parsing parseQueue = [[NSOperationQueue alloc] init]; // Make an operation to import the phonebook //[self setParseOp:[[ParseOperation alloc] initAndStartParse]]; [self setParseOpAD:[[ParseOperationA_D alloc] initAndStartParse]]; [self setParseOpEK:[[ParseOperationE_K alloc] initAndStartParse]]; [self setParseOpLR:[[ParseOperationL_R alloc] initAndStartParse]]; [self setParseOpSZ:[[ParseOperationS_Z alloc] initAndStartParse]]; // [parseQueue addOperation:parseOp]; NSArray *opArray = [[NSArray alloc] initWithObjects:parseOpAD, parseOpEK, parseOpLR, parseOpSZ, nil]; [parseQueue addOperations:opArray waitUntilFinished:NO]; } // self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // // Override point for customization after application launch. // self.window.backgroundColor = [UIColor whiteColor]; // [self.window makeKeyAndVisible]; return YES; } </code></pre> <p>Here is one of the NSOperation Classes (they are all the same, just working on different files to help speed up the initial loading of 6000 records.</p> <pre><code>#import "ParseOperationA-D.h" #import "ACHPhonebook.h" #import "AppDelegate.h" #import "TBXML.h" @implementation ParseOperationA_D - (id)initAndStartParse { NSLog(@"ParseOperation init"); // [self parsePhonebook]; return self; } - (void)mergeChanges:(NSNotification *)notification { id appDelegate = [[UIApplication sharedApplication] delegate]; NSManagedObjectContext *mainContext = [appDelegate managedObjectContext]; // Merge changes into the main context on the main thread [mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:) withObject:notification waitUntilDone:NO]; // NSLog(@"Merged Changes"); } // the main function for this NSOperation, to start the parsing - (void)main { id appDelegate = [[UIApplication sharedApplication] delegate]; NSManagedObjectContext *ctx = [[NSManagedObjectContext alloc] init]; [ctx setUndoManager:nil]; [ctx setPersistentStoreCoordinator: [appDelegate persistentStoreCoordinator]]; // Register context with the notification center NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; [nc addObserver:self selector:@selector(mergeChanges:) name:NSManagedObjectContextDidSaveNotification object:ctx]; NSUInteger x = 1; TBXML *tbxml = [[TBXML alloc] initWithXMLFile:@"achcentral_aTOd.xml"]; // Get root element TBXMLElement * root = tbxml.rootXMLElement; // if root element is valid if (root) { NSError *error = nil; TBXMLElement *thisPBE = [TBXML childElementNamed:@"PhoneBookResults" parentElement:root]; while (thisPBE != nil) { // Set up the Insert command ACHPhonebook * xmlPBE = (ACHPhonebook *)[NSEntityDescription insertNewObjectForEntityForName:@"ACHPhonebook" inManagedObjectContext:ctx]; // Set all the field values from the XML record // TBXMLElement *elName = [TBXML childElementNamed:@"Name" parentElement:thisPBE]; // if (elName != nil) { // [xmlPBE setName:[TBXML textForElement:elName]]; // } TBXMLElement *elTitle = [TBXML childElementNamed:@"title" parentElement:thisPBE]; if (elTitle != nil) { [xmlPBE setTitle:[TBXML textForElement:elTitle]]; } TBXMLElement *elDept = [TBXML childElementNamed:@"department" parentElement:thisPBE]; if (elDept != nil) { // obtain the text from the description element [xmlPBE setDepartment:[TBXML textForElement:elDept]]; } TBXMLElement *elExt = [TBXML childElementNamed:@"phone" parentElement:thisPBE]; if (elExt != nil) { [xmlPBE setExt:[TBXML textForElement:elExt]]; } TBXMLElement *elPager = [TBXML childElementNamed:@"pager" parentElement:thisPBE]; if (elPager != nil) { [xmlPBE setPager:[TBXML textForElement:elPager]]; } TBXMLElement *elEmailAddress = [TBXML childElementNamed:@"emailaddress" parentElement:thisPBE]; if (elEmailAddress != nil) { [xmlPBE setEmailAddress:[TBXML textForElement:elEmailAddress]]; } // TBXMLElement *elNetworkID = [TBXML childElementNamed:@"NetworkID" parentElement:thisPBE]; // if (elNetworkID != nil) { // [xmlPBE setNetworkid:[TBXML textForElement:elNetworkID]]; // } TBXMLElement *elLastName = [TBXML childElementNamed:@"lastName" parentElement:thisPBE]; if (elLastName != nil) { [xmlPBE setLastName:[TBXML textForElement:elLastName]]; } TBXMLElement *elFirstName = [TBXML childElementNamed:@"firstName" parentElement:thisPBE]; if (elFirstName != nil) { [xmlPBE setFirstName:[TBXML textForElement:elFirstName]]; } if (elFirstName != nil &amp;&amp; elLastName !=nil) { // Make the name field from the first and last names NSString *fullName = [[TBXML textForElement:elFirstName] stringByAppendingFormat:@" %@",[TBXML textForElement:elLastName]]; [xmlPBE setName:fullName]; } TBXMLElement *elPicLoc = [TBXML childElementNamed:@"picFileName" parentElement:thisPBE]; if (elPicLoc != nil) { if (![[TBXML textForElement:elPicLoc] isEqualToString:@""]) { [xmlPBE setPicloc:[TBXML textForElement:elPicLoc]]; NSString *picFilePath = @"https://secure.archildrens.org/insite/badgepics/adbadgepics/"; NSURL *url = [NSURL URLWithString:[picFilePath stringByAppendingString:xmlPBE.picloc]]; NSData * imageData = [[NSData alloc] initWithContentsOfURL: url]; if (!imageData) { // The image filename was stored but didn't exist NSString *achImage = [[NSBundle mainBundle] pathForResource:@"ach" ofType:@"png"]; imageData = [NSData dataWithContentsOfFile:achImage]; } [xmlPBE setPicture:imageData]; } } if (x % 50 == 0) { // Get ready to save the context error = nil; // Save the context. if (![ctx save:&amp;error]) { NSLog(@"loadPhoneBook error %@, %@", error, [error userInfo]); abort(); } // Clear out the scratchpad [ctx reset]; //NSLog(@"Got 10"); } // Find the next XML record (this will end the while loop when we reach the end) thisPBE = [TBXML nextSiblingNamed:@"PhoneBookResults" searchFromElement:thisPBE]; // Increment the counter x++; } // while ... if ([ctx hasChanges]) { // NSUInteger *left = [[ctx insertedObjects] count]; error = nil; // Save the context. if (![ctx save:&amp;error]) { NSLog(@"loadPhoneBook error %@, %@", error, [error userInfo]); abort(); } // Clear out the scratchpad [ctx reset]; NSLog(@"Got the last ones, %d", x); } } } @end </code></pre> <p>I have tried enabling <code>NSZombies</code> and still can't see what is going on. It always breaks with a <code>EXC_BAD_ACCESS</code> error on the </p> <pre><code>[parseQueue addOperations:opArray waitUntilFinished:NO]; </code></pre> <p>line in the <code>AppDelegate</code>, this was my first attempt at multithreading in an iOS app. Like I said before, I have a version that runs that was built against an older version of the SDK and it still runs. This may be (and probably is) something really simple that I am overlooking...</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload