Перерыв на EXC_BAD_ACCESS в XCode?
Я новичок в разработке iPhone и XCode в целом и понятия не имею, как начать поиск и устранение неисправностей сигнала EXC_BAD_ACCESS
. Как я могу заставить XCode разбиться на точную строку, вызывающую ошибку?
Я не могу заставить XCode останавливаться на строке, вызывающей проблему, но я вижу следующие строки в моей консоли отладки:
Sun Oct 25 15:12:14 jasonsmacbook TestProject [1289]: CGContextSetStrokeColorWithColor: недопустимый контекст
Sun Oct 25 15:12:14 jasonsmacbook TestProject [1289]: CGContextSetLineWidth: недопустимый контекст
Sun Oct 25 15:12:14 jasonsmacbook TestProject [1289]: CGContextAddPath: недопустимый контекст
Sun Oct 25 15:12:14 jasonsmacbook TestProject [1289]: CGContextDrawPath: недопустимый контекст
2009-10-25 15: 12: 14,680 LanderTest [1289: 207] *** - [CFArray objectAtIndex:]: сообщение, отправленное deallocated instance 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. Кажется, нет никакого консенсуса относительно того, какой путь является лучшим.
Ответы
Ответ 1
Для любых ошибок EXC_BAD_ACCESS вы обычно пытаетесь отправить сообщение выпущенному объекту. BEST способ отслеживания этих действий используется NSZombieEnabled.
Это работает, никогда не выпуская какой-либо объект, а завершая его как "зомби" и устанавливая внутри него флаг, который говорит, что он, как правило, был бы выпущен. Таким образом, если вы попытаетесь получить к нему доступ еще раз, он все еще знает, что это было до того, как вы сделали ошибку, и с этой небольшой информацией вы обычно можете отступить, чтобы узнать, в чем проблема.
Это особенно помогает в фоновых потоках, когда отладчик иногда обманывает любую полезную информацию.
ОЧЕНЬ ВАЖНО ДЛЯ ЗАМЕЧАНИЯ, однако, вам нужно 100% убедиться, что это только в вашем отладочном коде, а не в вашем коде распространения. Поскольку ничто никогда не выпускается, ваше приложение будет течь, течет и течет. Чтобы напомнить мне сделать это, я ввел этот журнал в свой appdelegate:
if(getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled"))
NSLog(@"NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled enabled!");
Если вам нужна помощь в поиске точной строки, сделайте Build-and-Debug (CMD-Y) вместо Build-and-Run ( CMD-R). Когда приложение выйдет из строя, отладчик покажет вам, в какой строке и в сочетании с NSZombieEnabled, вы должны точно узнать почему.
Ответ 2
О вашем массиве. Строка
NSMutableArray *array = [NSMutableArray array];
фактически не дает вам сохраненный объект, а скорее объект autorelease. Вероятно, он сохраняется в следующей строке, но затем вы не должны отпускать его в третьей строке. См. this
Это основное правило:
Вы получаете право собственности на объект, если его создаете с помощью метода, имя которого начинается с "alloc" или "new" или содержит "copy" (например, alloc, newObject или mutableCopy), или если вы отправляете сохранить сообщение. Вы несете ответственность за отказ от владения собственными вами объектами с помощью выпуска или авторекламы. В любой другой момент, когда вы получаете объект, вы не должны его отпускать.
Ответ 3
В Xcode 4 вы можете включить Zombies, нажав на раскрывающийся список Scheme (вверху слева, рядом с кнопкой остановки) → Edit Scheme → вкладка Diagnostics → Enable Zombie Objects
Ответ 4
Xcode/gdb всегда ломается на EXC_BAD_ACCESS
, вам просто нужно поработать над стеком вызовов, чтобы найти код, который его вызвал.
Обратите внимание, что такие ошибки часто возникают с объектами autoreleased
, что означает, что конечная причина проблемы не будет в стеке вызовов, вызвавшем EXC_BAD_ACCESS
. Это, когда NSZombieEnabled и NSAutoreleaseFreedObjectCheckEnabled становятся полезными.
Ответ 5
Новый ответ на старый поток... в XCode 4 наиболее эффективным способом диагностики исключений EXC_BAD_ACCESS является использование инструментов для профилирования вашего приложения (из XCode нажмите "Продукт/Профиль" и выберите "Зомби" ). Это поможет вам идентифицировать сообщения, отправленные на освобожденные объекты.
Ответ 6
Из классов Stanford CS193P: если вы добавили точку останова (вручную, отредактировав контрольные точки) для символа objc_exception_throw
, вы можете получить гораздо лучшее представление о том, что пошло не так, - позволяя всем переходить к точке, где отладчик останавливается сам имеет тенденцию затушевывать вещи и испортить трассировку стека. Когда вы останавливаетесь в objc_exception_throw, вы можете часто оглядываться назад на то, какой доступ/операция вызвали вашу проблему.
Ответ 7
Другим полезным подходом являются точки останова, которые будут запускаться непосредственно после возникновения исключения:
Откройте окно точек останова (Run - Show - Breakpoints) и добавьте две символические точки останова, называемые "objc_exception_throw" и "[NSException raise]"
От: http://blog.emmerinc.be/index.php/2009/03/19/break-on-exception-in-xcode/
Ответ 8
Просто хотел добавить для тех, кто приходит из Интернета, ища решения для одной и той же ошибки, но с другой ошибкой. В моем случае я получил ту же ошибку, когда я попытался создать NSDictionary с опечаткой в ключевом названии, где я забыл добавить "@" перед моим ключом:
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys: myObj1, @"goodKey", myObj2, "badkey @ is missing in front", nil];
Ответ 9
Надеюсь, я не пропустил идентичный ответ, но я обнаружил, что некоторые проекты могут выбросить эту ошибку из-за запуска на симуляторах для более старых версий iOS, которые могут быть несовместимы с зависимостью проекта или структурой. Я слишком долго гонялся за одним из них, прежде чем осознать, что это происходит только в версиях -больших симуляторов, таких как iPhone 4S, приложение даже не должно пытаться поддерживать.
Было бы неплохо получить более подробное сообщение об ошибке, но я бы предположил, что ответственность за структуру, в которой она возникла... Во всяком случае, это довольно обычная посылка для поиска, и, возможно, это поможет кому-то goofing так сильно, как я себя нашел.
Ответ 10
Перед тем, как включить зомби, я рекомендую сначала избавиться от всех предупреждений (если они есть). Простые вещи, такие как не пустое функционирование без return
, могут вызвать эту ошибку. Если у вас нет предупреждений, как говорят другие ответы.