Перерыв на EXC_BAD_ACCESS в XCode? - PullRequest
       39

Перерыв на EXC_BAD_ACCESS в XCode?

45 голосов
/ 26 октября 2009

Я новичок в разработке для iPhone и XCode в целом и не знаю, как начать устранение неисправностей сигнала EXC_BAD_ACCESS. Как я могу заставить XCode прерываться в точной строке, которая вызывает ошибку?


Я не могу заставить XCode остановиться на линии, вызывающей проблему, но я вижу следующие строки в моей консоли отладки:

вс 25 октября 15:12:14 jasonsmacbook TestProject [1289]: CGContextSetStrokeColorWithColor: неверный контекст

вс 25 октября 15:12:14 jasonsmacbook TestProject [1289]: CGContextSetLineWidth: недопустимый контекст

вс 25 октября 15:12:14 jasonsmacbook TestProject [1289]: CGContextAddPath: недопустимый контекст

вс 25 октября 15:12:14 jasonsmacbook TestProject [1289]: CGContextDrawPath: недопустимый контекст

2009-10-25 15: 12: 14.680 LanderTest [1289: 207] *** - [CFArray objectAtIndex:]: сообщение отправлено освобожденный экземпляр 0x3c4e610

Теперь я пытаюсь нарисовать контекст, который я извлекаю из UIGraphicsGetCurrentContext(), и перехожу к объекту, с которым я хочу рисовать.


Дальнейшая отладка методом проб и ошибок, и я обнаружил, что NSMutableArray У меня есть свойство, которое в моем классе было зомби. Я вошел в функцию init для класса и вот код, который я использовал:

if ((self = [super init])) {
        NSMutableArray *array = [NSMutableArray array];
        self.terrainBlocks = array;
        [array release];
    }
    return self;    
}

Я удалил строку [array release], и она больше не дает мне сигнал EXC_BAD_ACCESS, но теперь я не понимаю, почему это работает. Я подумал, что когда я использовал это свойство, оно автоматически сохранило его для меня, и поэтому я должен выпустить его из init, чтобы у меня не было утечки. Я полностью сбит с толку о том, как это работает, и все руководства и вопросы Stackoverflow, которые я прочитал, только сбивают меня с толку больше о том, как устанавливать свойства внутри моего метода init. Кажется, нет единого мнения о том, какой путь является лучшим.

Ответы [ 10 ]

84 голосов
/ 26 октября 2009

Для любых ошибок EXC_BAD_ACCESS вы обычно пытаетесь отправить сообщение освобожденному объекту. ЛУЧШИЙ способ отследить это - использовать NSZombieEnabled .

Это работает, никогда не выпуская объект, а заключая его в «зомби» и устанавливая внутри него флаг, который говорит, что обычно он был бы выпущен. Таким образом, если вы попытаетесь снова получить к нему доступ, он все еще будет знать, что было до того, как вы допустили ошибку, и с помощью этой небольшой информации вы обычно можете вернуться назад, чтобы увидеть, в чем проблема.

Это особенно помогает в фоновых потоках, когда отладчик иногда выбрасывает любую полезную информацию.

ОЧЕНЬ ВАЖНО ЗАМЕЧАНИЕ однако, вам нужно на 100% убедиться, что это только в вашем отладочном коде, а не в коде дистрибутива. Поскольку ничего не выпущено, ваше приложение будет течь и течь и течь. Чтобы напомнить мне сделать это, я поместил этот журнал в моем appdelegate:

if(getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled"))
  NSLog(@"NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled enabled!");

Если вам нужна помощь в поиске точной строки, выполните Build-and-Debug ( CMD-Y ) вместо Build-and-Run ( CMD-R ). Когда приложение падает, отладчик покажет вам, какая именно строка и в сочетании с NSZombieEnabled, вы сможете точно узнать, почему.

17 голосов
/ 26 октября 2009

О вашем массиве. Линия

NSMutableArray *array = [NSMutableArray array];

фактически не дает вам сохраненный объект, а скорее объект автоматического выпуска. Вероятно, он будет сохранен в следующей строке, но тогда вы не должны выпускать его в третьей строке. Смотри это

Это фундаментальное правило:

Вы вступаете во владение объектом, если создаете его с помощью метода, имя которого начинается с «alloc» или «new» или содержит «copy» (например, alloc, newObject или mutableCopy), или если вы отправляете ему сохранить сообщение. Вы несете ответственность за отказ от владения принадлежащими вам объектами с помощью выпуска или автоматического выпуска. В любое другое время, когда вы получаете объект, вы не должны отпускать его.

10 голосов
/ 10 ноября 2011

В Xcode 4 вы можете включить зомби, щелкнув раскрывающийся список Схема (вверху слева, справа рядом с кнопкой остановки) -> Изменить схему -> Вкладка диагностики -> Включить объекты зомби

7 голосов
/ 26 октября 2009

Xcode / gdb всегда работает на EXC_BAD_ACCESS, вам просто нужно пройтись вверх по стеку вызовов, чтобы найти код, который его вызвал.

Обратите внимание, что ошибки такого рода часто возникают с autoreleased объектами, а это означает, что основной причиной проблемы не будет стек вызовов, вызвавший EXC_BAD_ACCESS. Вот тогда станут полезными NSZombieEnabled и NSAutoreleaseFreedObjectCheckEnabled.

5 голосов
/ 15 ноября 2011

Новый ответ на старую ветку ... в XCode 4 наиболее эффективный способ диагностики исключений EXC_BAD_ACCESS - это использование инструментов для профилирования вашего приложения (в XCode нажмите Product / Profile и выберите Zombies). Это поможет вам идентифицировать сообщения, отправленные на освобожденные объекты.

2 голосов
/ 23 мая 2010

Еще один полезный подход - установка точек останова, которые будут срабатывать сразу после возникновения исключения:

Откройте окно точек останова (Выполнить - Показать - Точки останова) и добавьте две символические точки останова, названные «objc_exception_throw» и «[Повышение NSException]»

От: http://blog.emmerinc.be/index.php/2009/03/19/break-on-exception-in-xcode/

2 голосов
/ 26 октября 2009

Из классов Stanford CS193P: если вы добавите точку останова (вручную, путем редактирования точек останова) для символа objc_exception_throw, вы сможете получить гораздо более точное представление о том, что пошло не так - позволяя вещам перейти к точке, в которой отладчик останавливается с помощью само по себе имеет тенденцию затенить вещи и испортить след стека. Когда вы останавливаетесь в objc_exception_throw, вы часто можете вспомнить, какой именно доступ / операция вызвали вашу проблему.

1 голос
/ 23 сентября 2016

Я надеюсь, что не пропустил идентичный ответ, но я обнаружил, что некоторые проекты могут выдать эту ошибку из-за запуска на симуляторах для более старых версий iOS, которые могут быть несовместимы с зависимостью или структурой проекта. Я слишком долго гнался за одним из них, прежде чем понял, что это просто происходит в версиях -older-simulator, таких как iPhone 4S, приложение даже не должно было пытаться поддерживать.

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

1 голос
/ 13 августа 2011

Просто хотел добавить для тех, кто приходит из сети, ищет решения для той же ошибки, но с другой ошибкой. В моем случае я получил ту же ошибку, когда пытался создать экземпляр NSDictionary с опечаткой в ​​имени ключа, где я забыл добавить «@» перед моим ключом:

NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys: myObj1, @"goodKey", myObj2, "badkey @ is missing in front", nil];
0 голосов
/ 26 марта 2014

Перед включением зомби я рекомендую сначала избавиться от всех предупреждений (если они есть). Простые вещи, такие как не пустая функция без return, могут вызвать эту ошибку. Если у вас нет предупреждений, продолжайте, как предлагают другие ответы.

...