У меня есть приложение, которое отлично работает в старом проекте (которое не использует ARC и было написано в Xcode 4.0 с iOS 4.2.
Я пытаюсь перенести это приложение на использование ARC и раскадровки с Xcode 4.2 и iOS 5.
У меня все перенесено и исправлено все ошибки, вызванные сохранением, освобождением, освобождением и т. Д. Теперь проект работает нормально. Я также перестроил свою модель базовых данных в новом проекте и перестроил подклассы моей модели.
Ошибка возникает, когда я пытаюсь проанализировать файл XML в фоновом потоке. Файл является локальным для проекта. Я NSLog инициализатор для каждого класса NSOperation, который выполняет синтаксический анализ (их четыре). Я добираюсь до этой точки приложения, ошибка возникает, когда я добавляю операции в очередь.
Вот мой код в AppDelegate, который запускает Операции:
#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:&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;
}
Вот один из классов NSOperation (они все одинаковые, просто работают над разными файлами, чтобы помочь ускорить начальную загрузку 6000 записей.
#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 && 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:&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:&error])
{
NSLog(@"loadPhoneBook error %@, %@", error, [error userInfo]);
abort();
}
// Clear out the scratchpad
[ctx reset];
NSLog(@"Got the last ones, %d", x);
}
}
}
@end
Я попытался включить NSZombies
и до сих пор не вижу, что происходит. Он всегда прерывается с ошибкой EXC_BAD_ACCESS
на
[parseQueue addOperations:opArray waitUntilFinished:NO];
строка в AppDelegate
, это была моя первая попытка многопоточности в приложении для iOS. Как я уже говорил, у меня есть версия, которая работает на более старой версии SDK, и она все еще работает. Это может быть (и, вероятно, так) нечто очень простое, что я упускаю из виду ...