Получение EXC_BAD_ACCESS без каких-либо полезных сообщений от NSZombieEnabled

Я новичок в разработке iphone, и я боролся с ошибкой EXC_BAD_ACCESS, которую я получил пару дней назад. Я в основном беру класс iphone из Стэнфорда независимо и пытаюсь передать массив NSManagedObjects в TableViewController, который должен их отображать. Приложение запускается в симуляторе и отображает данные в tableView, но сразу же выдает ошибку EXC_BAD_ACCESS.

Я следовал инструкциям здесь и в других местах о том, как использовать NSZombieEnabled для выявления преждевременно выпущенных объектов, но этот приходит без каких-либо полезных сообщений даже с NSZombieEnabled. Я предполагаю, что это должно быть вызвано тем, что что-то пытается получить доступ к нераспределенной памяти, которая не была освобождена через выпуск/автоматический выпуск. В противном случае он был бы воспринят как объект-зомби, как и другие ошибки, которые мне удалось исправить. Я не эксперт по c, но означает ли это, что что-то подобное может произойти, если я объявлю объект и отправлю ему сообщение, даже не создав его экземпляр? Я просмотрел свой код, чтобы увидеть, есть ли у меня что-то подобное, и я оказался пустым.

У меня есть трассировка стека в отладчике для этого, но я не уверен, как ее использовать. Я немного расстроен, потому что не могу использовать точки останова в коде, чтобы еще больше сузить проблему, поскольку кажется, что это происходит после завершения загрузки приложения. Я думал, что приложение будет просто бездействовать, если не будет возможного взаимодействия с пользователем. Это выходит из строя в конце загрузки, где я не могу легко увидеть это, или просто делаю что-то в фоновом режиме после завершения загрузки. И я был бы очень признателен за любые советы о том, как читать трассировку стека для этого.

Я набрал свою трассировку стека ниже (не мог понять, как скопировать ее из отладчика)

0 objc_msgSend
1 ??
2 -[NSManagedObject dealloc]
3 -[_PFManagedObjectReferenceQueue _processReferenceQue:]
4 _performRunLoopAction
5 ___CFRunLoopDoObservers
6 CFRunLoopRunSpecific
7 CFRunLoopRunInMode
8 GSEventRunModal
9 GSEventRun
10 UIApplicationMain
11 main

И два основных класса в моей программе — это класс делегата верхнего уровня и вызываемый им ViewTableController.

`- (void)applicationDidFinishLaunching:(UIApplication *)application {

self.tabBarController = [[[UITabBarController alloc] init] autorelease];        

UINavigationController *contactsNavigationController = [[self createContactsNavigationController] retain];

//UINavigationController *recentsNavigationController = [[self createRecentsNavigationController:photos] retain];

tabBarController.viewControllers = [[NSArray alloc] initWithObjects: contactsNavigationController, nil];

[contactsNavigationController release];
//[recentsNavigationController release];

[window addSubview:tabBarController.view];
    [window makeKeyAndVisible];

}

-(UINavigationController *)createContactsNavigationController {

UINavigationController *contactsNavigationController = [[UINavigationController alloc] init];

UITabBarItem *contactsTabBarItem = [[UITabBarItem alloc] initWithTabBarSystemItem: UITabBarSystemItemContacts tag:0];
contactsNavigationController.tabBarItem=contactsTabBarItem ;
[contactsTabBarItem  release];


PersonListViewController *personListViewController = [[PersonListViewController alloc] initWithStyle:UITableViewStylePlain];    

NSManagedObjectContext *context = [self managedObjectContext];
personListViewController.managedObjectContext=context;

personListViewController.contacts = [self createContacts];
[context release];

personListViewController.title=@"Contacts";

[contactsNavigationController pushViewController:personListViewController animated:false];
return [contactsNavigationController autorelease];

}`

`- (NSArray *) readContacts {

NSString *path = [[NSBundle mainBundle] bundlePath];

NSString *filePath = [path stringByAppendingPathComponent:@"FakeData.plist"];
NSArray *plist = [[NSMutableArray arrayWithContentsOfFile:filePath] retain];

return [plist autorelease];
}

- (NSMutableArray *)createContacts {

NSArray * plist = [[self readContacts] retain
NSMutableArray *contactNames = [[NSMutableArray alloc] init];
NSMutableArray *contacts = [[NSMutableArray alloc] init];
for (NSDictionary *photo in plist) {
    NSString *contactName = [photo objectForKey:@"user"];
    Person *contact = nil;
    if (![contactNames containsObject:contactName]) {
        contact  = (Person *)[NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:managedObjectContext];
        contact.name =contactName;
        NSError *error;
        if (![managedObjectContext save:&error]) {
            NSLog(@"SHIT the save person FAILED!!!  %@",error);
        }

        [contacts addObject:contact];
        [contactNames addObject:contactName];



    } else {
        contact = [contacts objectAtIndex:[contactNames indexOfObject:contactName]];
    }

    [contactName release];

    Photo *image = (Photo *)[NSEntityDescription insertNewObjectForEntityForName:@"Photo" inManagedObjectContext:managedObjectContext];

    image.imageFile = [photo objectForKey:@"path"];
    image.imageName = [photo objectForKey:@"name"];
    image.owner = contact;

    contact.photos = [NSSet setWithObjects:image,nil];


     NSError *error;
     if (![managedObjectContext save:&error]) {
         NSLog(@"SHIT the save photoFAILED!!!  %@",error);
     }

    [image release];
    [contact release];
}

[plist release];

return [contacts autorelease];
}

Я извиняюсь, если мой код слишком дрянной для чтения.

Спасибо за помощь, ребята!


person Nefsu    schedule 17.03.2010    source источник
comment
Можете ли вы показать нам обратную трассировку и код, связанный с ней?   -  person Carl Norum    schedule 17.03.2010


Ответы (2)


Вот ваша проблема:

NSString *contactName = [photo objectForKey:@"user"];
... a bunch of lines later
[contactName release];

objectForKey: возвращает объект autoreleased, его не следует освобождать.

Точно так же insertNewObjectForEntityForName:inManagedObjectContext:managedObjectContext возвращает объект autoreleased, поэтому удалите [image release] и [contact release].

person Steven Canfield    schedule 17.03.2010
comment
Я не знаю, что сказать. Вы спасатель. Итак, если я правильно понял, мой [выпуск contactName] не выдавал исключение, потому что у меня все еще было значение continueCount, равное 1, из объекта с автоматическим освобождением, но как только пул был очищен, автоматическое освобождение не удалось, потому что я уже установил его сохранитьCount на 0. Как я могу отловить подобные ошибки в будущем, если я не знаю, где очищается пул, или мне просто нужно лучше управлять своей памятью. Извините, я пришел из мира Java и немного расстроен. Спасибо хоть. Это было здорово. - person Nefsu; 17.03.2010
comment
Во-первых, хорошая работа, ваше объяснение в этом комментарии правильное. Во-вторых, с некоторой практикой вы научитесь делать это лучше. Правило Если вы видите alloc или copy, вы должны увидеть сбалансированный релиз. В противном случае он выпускается автоматически, поэтому вам не нужно ничего с ним делать, если только вы не хотите его сохранить (сохранить). Для поиска ошибок автоматического выпуска одна вещь, которая может помочь в большей кодовой базе, — это добавление NSAutoreleasePools. Например: NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; // Делаем что-нибудь [слив пула]; Теперь вы рухнете на -drain, что сделает очевидным то, на чем вы падаете. - person Steven Canfield; 17.03.2010
comment
Спасибо. Я действительно видел пример кода, который делает локальные пулы. Я попробую. Еще раз спасибо. - person Nefsu; 17.03.2010

Я также получал EXC_BAD_ACCESS без какого-либо полезного сообщения, хотя NSZombieEnabled был проверен. Итак, хочу поделиться опытом:

После нескольких часов борьбы с симулятором я решил установить его на устройство. Сообщение об ошибке, которое я получил при отладке устройства, было более полезным.

В конце концов, я заметил, что получаю ошибку EXC_BAD_ACCESS и странное поведение, потому что я переименовал пару файлов xib за день до этого. Я выбрал объект «Контроллер представления» для файла MainWindow.xib и исправил свойство Имя NIB. Затем все работало гладко.

person Topsakal    schedule 01.08.2012