Почему моя программа получает EXC_BAD_ACCESS в _class_isInitialized () во время objc_msgSend ()? - PullRequest
4 голосов
/ 08 июля 2010

Окончательное обновление : Оказывается, решение этой проблемы является удручающим. Перейдите в каталог .xcodeproj внутри своего проекта и удалите файлы <username>.mode1v3 и <username>.pbxuser. Это исправило это. Бу, Xcode.


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

У меня есть класс контроллера представления. У него есть пара свойств, ссылающихся на пару других контроллеров представления. Каждый загружается через метод доступа get по мере необходимости, например так:

- (NotesViewController *)notesViewController {
    if (notesViewController == nil) {
        notesViewController = [[NotesViewController alloc] initWithNibName:@"NotesViewController" bundle:nil];
    }
    return notesViewController;
}

Когда вы позже позвоните [self notesViewController], все хорошо. Однако этот перестал работать:

- (DateFieldController *)dateFieldController {
    NSLog(@"made it into the method at least ...");
    if (dateFieldController == nil) {
        NSLog(@"nib loader, don't let us down...");
        dateFieldController = [[DateFieldController alloc] initWithNibName:@"DateFieldController" bundle:nil];
    }
    return dateFieldController;
}

Когда этот метод вызывается так же, как и другие средства доступа, он взрывается, очевидно, во время загрузки пера, но, возможно, до него:

2010-07-08 11:44:58.029 MyApp[24404:207] made it into the method at least ...
2010-07-08 11:44:58.030 MyApp[24404:207] nib loader, don't let us down...
Program received signal:  “EXC_BAD_ACCESS”.
(gdb) bt
#0  0x028bb0ca in _class_isInitialized ()
#1  0x028b9eca in _class_initialize ()
#2  0x028bf1f6 in prepareForMethodLookup ()
#3  0x028b86c9 in lookUpMethod ()
#4  0x028b8836 in _class_lookupMethodAndLoadCache ()
#5  0x028c6ad3 in objc_msgSend ()
#6  0x00007bb3 in -[EntryViewController controllerForFieldType:] (self=0x7942d70, _cmd=0x190c20, type=0x79844b0) at /Users/wgray/Documents/Sources/iPhone/MyApp-iphone/Classes/EntryViewController.m:481
#7  0x00007e07 in -[EntryViewController selectTypesControllerDidSelect:] (self=0x7942d70, _cmd=0x190bb4, type=0x79844b0) at /Users/wgray/Documents/Sources/iPhone/MyApp-iphone/Classes/EntryViewController.m:527
#8  0x0000d2ad in -[TypesViewController tableView:didSelectRowAtIndexPath:] (self=0x5d2aac0, _cmd=0x1eac458, aTableView=0x6056000, indexPath=0x781c780) at /Users/wgray/Documents/Sources/iPhone/MyApp-iphone/Classes/TypesViewController.m:81
#9  0x0059e718 in -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] ()
#10 0x00594ffe in -[UITableView _userSelectRowAtIndexPath:] ()
#11 0x002abcea in __NSFireDelayedPerform ()
#12 0x0274cd43 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ ()
#13 0x0274e384 in __CFRunLoopDoTimer ()
#14 0x026aad09 in __CFRunLoopRun ()
#15 0x026aa280 in CFRunLoopRunSpecific ()
#16 0x026aa1a1 in CFRunLoopRunInMode ()
#17 0x02fd02c8 in GSEventRunModal ()
#18 0x02fd038d in GSEventRun ()
#19 0x0053ab58 in UIApplicationMain ()
#20 0x00001e24 in main (argc=1, argv=0xbffff050) at /Users/wgray/Documents/Sources/iPhone/MyApp-iphone/main.m:14
(gdb)

Похоже, что-то неприятное происходит в SDK Simulator при запуске метода загрузки пера. На самом деле, возможно, намного раньше. Перегрузка инициализатора загрузки пера с небольшим действием NSLog в DateFieldController ни к чему нас не приведет с подозрением:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    NSLog(@"come on, you...");
    if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) 
    {
    NSLog(@"rock on!");
  }
  return self;
}

Достаточно сказать, что ни одно из этих утверждений NSLog никогда не выполняется.

Так что же происходит? Почему время выполнения меня раздражает? (Переключение вызова с self.dateFieldController на [self dateFieldController] не устраняет ошибку - и помните, этот код точно такой же, как и в моей основной ветке, где он не падает).

FWIW, я строю с 64-битным XCode 3.2.3, компилирую для Simulator 4.0, Debug, i386 arch (на новом Mac Book Pro под управлением OS X 10.6.3), цель развертывания в настройках проекта установлена ​​на «iPhone OS 3.0» (при использовании 3.1.3 это тоже не исправляется).

Обновление: по запросу, реализация controllerForFieldType::

- (id)controllerForFieldType:(Type *)type {
    id controller = nil;

    if ([type.mode isEqualToString:@"note"]) {
        controller = self.notesViewController;
    } else if ([type.mode isEqualToString:@"date"]) {
        NSLog(@"going for it, attempting to load dateFieldController from accessor...");
        controller = self.dateFieldController;
    } else {
        controller = self.fieldViewController;
    }

    return controller;
}

Я пропустил это раньше, потому что я не думаю, что это особенно актуально, проблема, кажется, происходит позже в стеке, в реальном методе получения dateFieldController.

Обновление II: По предложению @ zneak я включил настройку Run -> Enable Guard Malloc и снова пробежался по сценарию. Результаты в основном одинаковы, но внутренняя обратная трассировка во время выполнения отличается. Может показаться, что что-то не так с Классом или NIB, которые мешают его декодированию:

2010-07-08 12:26:26.180 Strip[24961:207] made it into the method at least ...
2010-07-08 12:26:26.289 Strip[24961:207] nib loader, don't let us down...
Program received signal:  “EXC_BAD_ACCESS”.
Data Formatters temporarily unavailable, will re-try after a 'continue'. (Not safe to call dlopen at this time.)
(gdb) bt
#0  0x028cd41f in attachMethodLists ()
#1  0x028cdf77 in realizeClass ()
#2  0x028cedad in _class_getNonMetaClass ()
#3  0x028c8eb0 in _class_initialize ()
#4  0x028ce1f6 in prepareForMethodLookup ()
#5  0x028c76c9 in lookUpMethod ()
#6  0x028c7836 in _class_lookupMethodAndLoadCache ()
#7  0x028d5ad3 in objc_msgSend ()
#8  0x00007b81 in -[EntryViewController controllerForFieldType:] (self=0x38cfaf30, _cmd=0x190c8f, type=0x3cacbfe0) at /Users/wgray/Documents/Sources/iPhone/strip-iphone/Classes/EntryViewController.m:482
...snip...
#22 0x00001de4 in main (argc=1, argv=0xbfffefec) at /Users/wgray/Documents/Sources/iPhone/strip-iphone/main.m:14
(gdb)

Обновление III: В котором загущается заговор. По предложению @ ohorob в комментариях я добавил env arg OBJC_PRINT_INITIALIZE_METHODS = YES и обнаружил, что каждая инициализация класса в приложении выглядит хорошо, за исключением рассматриваемой здесь. Каждый из них выглядит примерно так в выводе консоли:

objc[26750]: INITIALIZE: calling +[UIPinchGestureRecognizer initialize]
objc[26750]: INITIALIZE: finished +[UIPinchGestureRecognizer initialize]
objc[26750]: INITIALIZE: UIPinchGestureRecognizer is fully +initialized

Когда я запускаю приложение и выбираю строку таблицы, которая приводит к взрыву, мы просто видим вывод консоли nslog до сбоя и сам сбой. Я хотел бы думать, что это означает, что мы могли бы исключить неправильную инициализацию, но мне не хватает эксперта по времени выполнения.

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

Ответы [ 2 ]

2 голосов
/ 08 июля 2010

Что-то идет не так, как надо, во время инициализации класса.

Попробуйте установить для переменной среды OBJC_PRINT_INITIALIZE_METHODS значение YES и запустить приложение.Это может дать нам подсказку.Или нет.(Установите переменную среды в исполняемом инспекторе XCode - см. документы ).

Есть ли у вас какие-либо методы +initialize?(в любом классе - может быть, один из ваших классов щекочет инициализацию чего-то, казалось бы, не связанного с падением)

1 голос
/ 08 июля 2010

Тот факт, что проблема продолжает двигаться, заставляет меня подозревать, что что-то давит на структуры данных внутреннего класса среды выполнения. Первое, что я заподозрил, это слишком умные занятия. У тебя нет классов, которые играют в игры с Иса? См. XMPPMessage.m для примера этого. Я не спрашиваю, играют ли эти классы контроллера представления с isa; Я имею в виду любой класс в системе, поскольку неправильное выполнение этих действий может привести к неожиданному нагромождению памяти.

Далее я бы попробовал использовать class_copyMethodList () и посмотреть, не произойдет ли это до вызова + alloc. Если это так, то ваша таблица классов определенно повреждена.

...