4 Stimmen

Warum erhält mein Programm EXC_BAD_ACCESS in _class_isInitialized() während einer objc_msgSend()?

Letzte Aktualisierung : Wie sich herausstellte, ist die Lösung für dieses Problem eine deprimierende Angelegenheit. Gehen Sie in das Verzeichnis .xcodeproj in Ihrem Projekt und entfernen Sie die <username>.mode1v3 und <username>.pbxuser Dateien. Das war's. Buh, Xcode.


Zunächst möchte ich sagen, dass es sich nicht um einen gewöhnlichen Fehler beim Behalten/Freigeben handelt. Es begann gerade auf einem Entwicklungszweig meines Codes zu passieren, der Fehler ist nicht auf dem Master-Zweig vorhanden, und ich habe Schwierigkeiten, irgendwelche Unterschiede in den Quellen zu finden, die auf die Antwort hinweisen. Also komme ich gleich zum Kern der Sache.

Ich habe eine View-Controller-Klasse. Es hat ein paar Eigenschaften, die ein paar andere Viewcontroller referenzieren. Jeder wird über Getter Accessor geladen, wie benötigt, wie so:

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

Wenn Sie später anrufen [self notesViewController] dann ist alles gut. Dieser hier hat jedoch einfach aufgehört zu funktionieren:

- (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;
}

Wenn diese Methode auf die gleiche Weise wie die anderen Accessoren aufgerufen wird, bricht sie ab, anscheinend während des Ladens der Feder, aber möglicherweise auch vorher:

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)

Es hat den Anschein, dass im Simulator-SDK etwas Unangenehmes passiert, wenn die Nib-Lademethode ausgelöst wird. In der Tat, möglicherweise viel früher. Das Überschreiben des Nib-Lade-Initialisierers mit einer kleinen NSLog-Aktion in der DateFieldController bringt uns verdächtig wenig weiter:

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

Es genügt zu sagen, dass keine dieser NSLog-Anweisungen jemals ausgeführt wird.

Was ist also los? Warum kotzt mich die Laufzeit an? (Umschalten des Aufrufs von self.dateFieldController a [self dateFieldController] behebt den Fehler nicht -- und bedenken Sie, dass dieser Code genau derselbe ist wie der in meinem Master-Zweig, wo er nicht abstürzt).

FWIW, ich baue mit XCode 3.2.3 64-Bit, kompilieren für Simulator 4.0, Debug, i386 arch (auf einem neuen Mac Book Pro mit OS X 10.6.3), Deployment Target in Projekteinstellungen ist auf "iPhone OS 3.0" (Uppping dies auf 3.1.3 behebt es auch nicht).

Aktualisierung: wie gefordert, die Umsetzung von 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;
}

Ich habe dies früher ausgelassen, weil ich nicht glaube, dass es besonders relevant ist, das Problem scheint später im Stapel zu passieren, in der eigentlichen Getter-Methode dateFieldController .

Update II: Auf Anraten von @zneak habe ich die Einstellung Run -> Enable Guard Malloc aktiviert und das Szenario erneut durchgespielt. Die Ergebnisse sind im Grunde die gleichen, aber der interne Backtrace in der Runtime ist anders. Es hat den Anschein, dass mit der Klasse oder der NIB etwas nicht stimmt, was verhindert, dass sie dekodiert wird:

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)

Update III: In dem sich die Handlung verdichtet. Auf den Vorschlag von @ohorob in den Kommentaren hin habe ich das env arg OBJC_PRINT_INITIALIZE_METHODS=YES hinzugefügt und festgestellt, dass jede einzelne Klasseninitialisierung in der App gut aussieht, außer der hier fraglichen. Jede sieht in der Konsolenausgabe ungefähr so aus:

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

Wenn ich die Anwendung ausführe und die Tabellenzeile auswähle, die zur Explosion führt, sehen wir nur die nslog-Konsolenausgabe vor dem Absturz und den Absturz selbst. Ich würde gerne denken, dass dies bedeutet, dass wir eine unsachgemäße Initialisierung ausschließen können, aber ich bin nicht genug Experte für die Laufzeit.

Ich habe eine gründliche Prüfung der Code-Unterschiede zwischen dem Master-Zweig und diesem Dev-Zweig durchgeführt und nichts gefunden, was darauf hindeutet, dass ich auf einen Zeiger getreten bin, aber ich denke, dass das am wahrscheinlichsten ist, was vor sich geht.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X