2016-04-15 9 views
2

Zuerst ein Disclaimer. #NotMyCode.Noch ein Objective-C EXC_BAD_ACCESS

Der folgende Ausdruck delegate.deviceToken löst manchmal eine schlechte Zeigerdereferenz aus, anscheinend aus objc_retain().

MyWebServices.m:

@implementation MyWebServices 

+ (void)initializeWithCompletionBlock:(void (^) (id data))completionBlock withErrorBlock:(void (^)(NSError* error))errorBlock { 
    AppDelegate* delegate = (AppDelegate*) [[UIApplication sharedApplication] delegate]; 

    if (delegate.deviceToken == nil) { // MyWebServices.m:29 
     ... 
    } 

    ... 

} 

Die AppDelegate erklärt deviceToken wie so:

@property (nonatomic, assign) NSString* deviceToken; // #NotMyCode 

Quoth der Absturzbericht:

Code Type:   ARM-64 (Native) 

Exception Type: EXC_BAD_ACCESS (SIGSEGV) 
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000f434c4388 
Triggered by Thread: 0 

0 libobjc.A.dylib      0x0000000180a940b0 objc_retain + 16 (objc-object.h:341) 
1 MyApp        0x0000000100054f98 +[MyWebServices initializeWithCompletionBlock:withErrorBlock:] + 200 (MyWebServices.m:29) 
2 MyApp        0x000000010003b97c -[AppDelegate initializeWebServices] + 224 (AppDelegate.m:380) 
3 MyApp        0x00000001000b123c __47-[AFNetworkReachabilityManager startMonitoring]_block_invoke + 132 (AFNetworkReachabilityManager.m:199) 

Der Anruf an -[AppDelegate initializeWebServices] kann aus dem AFNetworkReachabilityManager Code, wie es in diesem Fall oder aus meinem application:didRegisterForRemoteNotificationsWithDeviceToken herauskommt. Mein deviceToken ist in der Tat nicht initialisiert in AppDelegate, und so mit seiner assign Semantik scheint es klar, dass ich versuche, Müll zu dereferenzieren. Aber wie verursacht der Null-Check einen Anruf an objc_retain?

Es lohnt sich eindeutig zu versuchen, deviceToken zu nil zu initialisieren oder seine Speicherverwaltungssemantik zu aktualisieren. Bemerkenswert im Code sind auch ein paar Boolesche, deren Absicht der Schutz von Anrufen zu scheint, und die schlecht verwaltet werden können.

Aber ich habe keine Ahnung, wie diesen Fehler zu reproduzieren, und die App wird von Millionen jeden Monat verwendet. Ich bin sehr dankbar für alle Einsichten, die mir helfen, es in der nächsten Version richtig zu machen.

+1

Wenn Sie sich auf deviceToken innerhalb eines Blocks beziehen, wird in der Tat ein Retain versucht, so dass der Wert von deviceToken während des Bereichs Ihres Blocks gültig ist. – nielsbot

+2

Ihr Eigentum sollte "kopieren" oder "stark" sein, nicht "zuweisen" – dan

+1

Auch wird der Null-Check hier nicht helfen, da Ihr Zeiger nicht Null ist. Es ist ein Zeiger auf ein nicht zugeordnetes Objekt. – nielsbot

Antwort

2

Die Eigenschaft ist falsch deklariert;

@property (nonatomic, strong) NSString* deviceToken; 

Verwendung assign bedeutet das Objekt nicht richtig, wird die Ausnahme daher beibehalten wird: es sollte das strong oder copy Attribut anstelle von assign verwenden.

+3

Eigenschaften vom Typ 'NSString' sollten fast immer mit' copy' Semantik deklariert werden (kein Problem hier). –

+0

@NikolaiRuhe Warum ist das? Wenn es darum geht sicherzustellen, dass das Objekt nicht * hinter Ihrem Rücken * (sozusagen) geändert wird, warum ist das dann auf 'NSString' beschränkt? – trojanfoe

+0

Es ist nicht auf NSString beschränkt (aber Typen, die 'NSCopying' entsprechen). Normalerweise wird dies für 'NSString' und die meisten Sammlungstypen gemacht. Diese Typen sind Klassencluster, in denen die unveränderlichen Unterklassen '-copy' als No-Op implementieren. So ist es billig, wenn es nicht notwendig und teuer ist, wenn es tatsächlich benötigt wird. –