2013-05-17 15 views
14

Sto sviluppando un'applicazione iOS 5.0+ con l'ultimo SDK.- [NSNull length]: selettore non riconosciuto inviato agli oggetti JSON

ottengo un errore molto strano con questo codice:

- (NSMutableURLRequest*)setupRequestWithService:(NSString*)service andMethod:(NSString*)method 
{ 
    NSString* url = [NSString stringWithFormat:@"%@%@.svc/%@", serverUrl, service, method]; 

    NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]]; 

    // Set authentication token. 
    NSLog(@"???????????? %@", authenticationToken); 
    if (authenticationToken == nil) 
     NSLog(@"NULL AUTHTOKEN"); 
    if ([authenticationToken isEqual:[NSNull null]]) 
     NSLog(@"NSNULL AUTHTOKEN"); 
    if (request == nil) 
     NSLog(@"NULL REQUEST"); 
    [request addValue:authenticationToken forHTTPHeaderField:REQUEST_HEADER_AUTH_TOKEN]; 

    return request; 
} 

Questo è il mio registro:

???????????? <null> 
NSNULL AUTHTOKEN 
-[NSNull length]: unrecognized selector sent to instance 0x3b5a5090 
    *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull length]: unrecognized selector sent to instance 0x3b5a5090' 

Sembra che authenticationToken è NULL. Ma non lo capisco, se authenticationToken è NULL perché non vedo NULL AUTHTOKEN nel registro.

Ho ricevuto questo errore la seconda volta che eseguo quel metodo, la prima volta, non ho alcun errore. Questo è il mio registro:

???????????? (null) 
NULL AUTHTOKEN 

A proposito:

NSString* authenticationToken; 

Qualche consiglio?

forse c'è una qualche parte ... Memory Leak

+0

è NSNullo, non è nulla. http://developer.apple.com/library/ios/#documentation/cocoa/reference/foundation/Classes/NSNull_Class/Reference/Reference.html – Kreiri

+0

È necessario verificare con ([NSNull null] == authenticationToken) {NSLog (@ "NULL AUTHTOKEN");} – Amar

+0

Sì, probabilmente l'autenticazione gothToken da JSON e aveva un valore null per quel valore, quindi un oggetto NSNull è ciò che ti viene dato. È possibile eseguire 'authenticationToken == [NSNull null]' per verificarlo, poiché nell'app c'è sempre esattamente un oggetto NSNull. –

risposta

77

La mia soluzione a questo uso esasperante di NSNull da interpreti JSON è quello di creare una categoria sulla NSNull, dove Definisco integerValue, floatValue, length, etc - restituisce 0 per tutti. Ogni volta che ottieni un altro incidente aggiungi una nuova categoria. Penso di avere 6 o 7 quando ho avuto questo problema.

Il problema con NON sta facendo questo è che devi cercare il NULL ovunque nei tuoi oggetti convertiti - una PITA secondo me.

EDIT: il codice che sto utilizzando, il tutto in un file NSNull + JSON.m:

@interface NSNull (JSON) 
@end 

@implementation NSNull (JSON) 

- (NSUInteger)length { return 0; } 

- (NSInteger)integerValue { return 0; }; 

- (float)floatValue { return 0; }; 

- (NSString *)description { return @"0(NSNull)"; } 

- (NSArray *)componentsSeparatedByString:(NSString *)separator { return @[]; } 

- (id)objectForKey:(id)key { return nil; } 

- (BOOL)boolValue { return NO; } 

@end 

EDIT2: Ora in Swift 3:

extension NSNull { 
    func length() -> Int { return 0 } 

    func integerValue() -> Int { return 0 } 

    func floatValue() -> Float { return 0 }; 

    open override var description: String { return "0(NSNull)" } 

    func componentsSeparatedByString(separator: String) -> [AnyObject] { return [AnyObject]() } 

    func objectForKey(key: AnyObject) -> AnyObject? { return nil } 

    func boolValue() -> Bool { return false } 
} 
+2

Lei signore è un genio. –

+2

Soluzione capolavoro. Wow :) –

+0

@ Pawan-Systematix ha appena aggiornato la mia risposta con il codice che sto usando. –

6

Il messaggio di errore è abbastanza chiaro. NSNull e nil sono cose diverse:

The NSNull class defines a singleton object used to represent null values in 
collection objects (which don’t allow nil values). 

Se si vuole verificare se authenticationToken è NSNull prova: [authenticationToken isEqual: [NSNull null]]

+0

Grazie per la risposta, ma non aiuta. Voglio solo sapere cosa sta succedendo! Ho un 'NSString' e poi cambia in' NSNull'. – VansFannel

+0

@VansFannel Allora dovresti fare quella domanda. – Mar0ux

2

In linea con la risposta di David H , che ne dici di una categoria su NSNull che utilizza l'inoltro dei messaggi di ObjC per "non fare nulla", per emulare il comportamento del runtime quando si inviano messaggi a nil?

Così:

@interface NSNull (ForwardInvocation) 

@end 

@implementation NSNull (ForwardInvocation) 

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { 
    return [NSNull methodSignatureForSelector:@selector(description)]; 
} 

- (void)forwardInvocation:(NSInvocation *)anInvocation { 
    // do nothing; prevent 'unrecognized selector' crashes 
} 

@end 

Il [NSNull methodSignatureForSelector:@selector(description)]; sfrutta il fatto che NSNull eredita da NSObject, che fornisce il metodo description. Questo soddisfa i requisiti del meccanismo di inoltro per l'implementazione di -methodSignatureForSelector:.

+0

Credo che questo non funzionerà. Quello che fa la mia soluzione è restituire un "nulla" digitato, in modo che il destinatario possa usare il valore nello stesso modo in cui sarebbe una risposta "reale". Nota in un caso viene restituito un array vuoto. Inoltre ottieni la descrizione univoca in modo da poter vedere i null durante il debug. –

+0

Funziona nel mio caso e sembra una soluzione più generica. Grazie! – Emilio

+0

@Emilio Grazie! –

0

Il problema si verifica perché il metodo restituisce un oggetto NSNull. Non è possibile controllare [authenticationToken isEqual:[NSNull null]]) perché [NSNull null] fornisce un'istanza di un oggetto.Quindi è diverso dal tuo oggetto stesso. Se si desidera verificare se è stato ricevuto un oggetto NSNull, è necessario controllare in questo modo: [authenticationToken isKindOfClass:[NSNull class]].

Problemi correlati