Подтвердить что ты не робот

Перерыв на 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. Кажется, нет никакого консенсуса относительно того, какой путь является лучшим.

4b9b3361

Ответ 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, могут вызвать эту ошибку. Если у вас нет предупреждений, как говорят другие ответы.