2010-09-15 28 views
18

Wie überprüfe ich, ob ein NSNumber-Objekt null oder leer ist?Überprüfen, ob NSNumber leer ist

OK nil ist einfach:

NSNumber *myNumber; 
if (myNumber == nil) 
    doSomething 

Aber wenn das Objekt erstellt wurde, aber es gibt keinen Wert darin, da eine Zuordnung fehlgeschlagen ist, wie kann ich das überprüfen? Verwenden Sie so etwas?

if ([myNumber intValue]==0) 
    doSomething 

Gibt es eine allgemeine Methode für Objekte auf Leere Prüfung wie für NSString verfügbar (siehe diese post)?

Beispiel 1

NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; 
[dict setValue:@"" forKey:@"emptyValue"]; 
NSNumber *emptyNumber = [dict objectForKey:@"emptyValue"]; 

Welchen Wert hat emptyNumber enthalten? Wie kann ich prüfen, ob emptyNumber leer ist?

Beispiel 2

NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; 
[dict setValue:@"" forKey:@"emptyValue"]; 
NSString *myString = [dict objectForKey:@"emptyValue"]; 
if (myString == nil || [myString length] == 0) 
    // got an empty value 
    NSNumber *emptyNumber=nil; 

Was passiert, wenn ich diese nach dem Gebrauch geschieht emptyNumber auf Null gesetzt wurde?

[emptyNumber intValue] 

Bekomme ich null?

Beispiel 3

NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; 
[dict setValue:@"" forKey:@"emptyValue"]; 
NSNumber *myEmptyValue = [dict objectForKey:@"emptyValue"]; 
if (myEmptyValue == nil) 
    // NSLog is never called 
    NSLog(@"It is empty!"); 

Wie diese Weise wird NSLog nie genannt. myEmptyValue ist nicht nil und nicht . Also enthält es eine willkürliche Zahl?

+0

@ [0.7] geben NSNumber, die definitiv nicht Null ist, aber intValue gibt 0 zurück. Das ist also ein schlechter Test. – gnasher729

+0

Upvoted für die großen Details, die dazu beigetragen haben, etwas zu erklären, mit dem ich es zu tun habe. NSNumber * savedPin = [[NSUserDefaults standardUserDefaults] valueForKey: @ "someKey"]; gibt ein Objekt zurück, das die Klasse __NSCFConstantString hat und somit Vergleiche mit nil fehlschlagen. VIELEN DANK! –

Antwort

12

NSValue, NSNumber, ... sollen aus einem Wert erstellt werden und immer einen halten. Das Testen auf einen bestimmten Wert wie 0 funktioniert nur, wenn es nicht im Bereich der gültigen Werte liegt, mit denen Sie arbeiten.

In dem seltenen Fall, in dem Code mehr geradlinig ist, mit zu arbeiten, wenn Sie einen Wert haben, „ungültig“ oder „nicht gesetzt“ und sie können nicht nil (zB mit den Standardcontainern darstellt) Sie können stattdessen NSNull verwenden.

In Ihrem ersten Beispiel könnte dies sein:

[dict setValue:[NSNull null] forKey:@"emptyValue"]; 

if ([dict objectForKey:@"emptyValue"] == [NSNull null]) { 
    // ... 
} 

Aber beachten Sie, dass Sie einfach nicht (oder entfernen) einfügen können diesen Wert, wenn Sie nil (dh nicht in dem Behälter) zu differenzieren müssen und, sagen, "ungültig":

if ([dict objectForKey:@"nonExistent"] == nil) { 
    // ... 
} 

Was das zweite Beispiel, -intValue give s Sie 0 - aber einfach, weil das Senden von Nachrichten an nil0 zurückgibt. Sie könnten auch 0 z.B. für eine NSNumber, deren intValue vorher auf 0 gesetzt wurde, was ein gültiger Wert sein könnte.
Wie oben bereits beschrieben, können Sie nur so etwas tun, wenn 0kein gültiger Wert für Sie ist. Beachten Sie die für Sie, was am besten funktioniert, hängt ganz davon ab, was Ihre Anforderungen sind.

mich Lassen Sie versuchen zusammenfassen:

Option # 1:

Wenn Sie alle Werte aus dem Bereich Zahlen nicht benötigen, können Sie ein (0 oder -1 oder verwenden könnte .. .) und -intValue/... um "leer" zu repräsentieren. Dies ist offensichtlich nicht der Fall für dich.

Option # 2:

Sie einfach nicht speichern oder die Werte aus dem Behälter entfernen, wenn sie "leer" sind:

// add if not empty: 
[dict setObject:someNumber forKey:someKey];  
// remove if empty: 
[dict removeObjectForKey:someKey]; 
// retrieve number: 
NSNumber *num = [dict objectForKey:someKey]; 
if (num == nil) { 
    // ... wasn't in dictionary, which represents empty 
} else { 
    // ... not empty 
} 

jedoch Dies bedeutet, dass keine da ist Unterschied zwischen Schlüsseln, die leer sind und Schlüsseln, die niemals existieren oder illegal sind.

Option # 3:

In einigen seltenen Fällen seiner bequemen alle Schlüssel im Wörterbuch zu halten und stellen „leer“ mit einem anderen Wert. Wenn Sie keinen aus dem Nummernkreis verwenden können, müssen wir etwas anderes eingeben, da NSNumber kein Konzept "leer" hat. Kakao hat bereits NSNull für solche Fälle:

// set to number if not empty: 
[dict setObject:someNumber forKey:someKey]; 
// set to NSNull if empty: 
[dict setObject:[NSNull null] forKey:someKey]; 
// retrieve number: 
id obj = [dict objectForKey:someKey]; 
if (obj == [NSNumber null]) { 
    // ... empty 
} else { 
    // ... not empty 
    NSNumber *num = obj; 
    // ... 
} 

Mit dieser Option können Sie jetzt zwischen „leer“, unterscheiden „nicht leer“ und „nicht in dem Behälter“ (zum Beispiel illegale Taste).

+0

in Betracht ziehen muss. Wie kann ich in diesem "Spezialfall" auf Leere testen? Liegt es hier im Bereich gültiger Werte? – testing

+0

Sie fügen '[NSNull null]' ein, um später ein NSNumber-Objekt auf Leere zu testen. OK, aber was sind Standardcontainer? Ich kann nicht garantieren, welcher Wert meinem NSNumber-Objekt zugewiesen ist. Ich weiß also nicht, wann ich 'nil' oder' NSNull' einfügen soll. In meinem Beispiel könnte es auch eine leere Zeichenfolge sein.Sollte ich zuerst den Rückgabewert von 'objectForKey' testen, wenn es eine leere Zeichenfolge ist, und dann sollte ich 'nil' oder 'NSNull' in mein NSNumber-Objekt einfügen? Ich denke, ich sollte immer Null einfügen, es sei denn, ich brauche NSNull für einige Fälle. Siehe mein zweites Beispiel. – testing

+1

@tests: Standardcontainer sind die von Cocoa Touch ('NSArray',' NSDictionary', ...). Das erste Beispiel testet, ob das Objekt 'NSNull' ist, das zweite setzt * voraus, dass Sie den Wert nicht in den Container * eingeben - Sie können in diese keine' nil' einfügen, 'nil' repräsentiert *" nicht im Container " *. Sie müssen lediglich entscheiden, ob Sie unterscheiden müssen zwischen * "ungültig" */* "nicht vorhanden" * und * "nicht im Container" *. Dein letzter Satz ist nahe an dem, was ich sage - entweder lege ihn nicht in den Container (so bekommst du 'nil' für' -objectForKey: ... ') oder geh mit' NSNull'. –

3

NSNumber ist entweder nil, oder es enthält eine Nummer, nichts dazwischen. "Leere" ist ein Begriff, der von der Semantik des jeweiligen Objekts abhängt und daher macht es keinen Sinn, nach einer allgemeinen Leerheitsüberprüfung zu suchen.

Wie für Ihre Beispiele, gibt es einige Dinge los:

NSMutableDictionary *hash = [NSMutableDictionary dictionary]; 
[hash setObject:@"" forKey:@"key"]; 
NSNumber *number = [hash objectForKey:@"key"]; 
NSLog(@"%i", [number intValue]); 

Die NSLog0 hier gedruckt werden, aber nur, weil es eine intValue Methode in NSString. Wenn Sie die Nachricht etwas ändern, nur NSNumber tun kann, wird der Code fehlschlagen:

NSLog(@"%i", [number unsignedIntValue]); 

Diese werfen:

-[NSCFString unsignedIntValue]: unrecognized selector sent to instance 0x303c 

Das bedeutet, Sie sind nicht einige allgemeine „leeren“ Wert bekommen Zurück von der Hash, erhalten Sie nur die NSString Sie dort gespeichert.

Wenn Sie eine leere (== nil) NSNumber haben und senden Sie eine Nachricht, wird das Ergebnis Null sein.Das ist einfach eine Sprachkonvention, die Code vereinfacht:

(array != nil && [array count] == 0) 
(someNumber == nil ? 0 : [someNumber intValue]) 

verwandelt sich in dieses:

([array count] == 0) 
([someNumber intValue]) 

Hoffnung, das hilft.

+0

Was macht NSNumber * test = [NSNull null]? –

+1

Wie geschrieben, macht dieser Code nicht viel Sinn. NSNull ist nur eine "Objektversion des Nullwertes" und der einzige Grund, warum es existiert, ist die Darstellung eines "leeren" Wertes in Sammlungen, die Nil nicht direkt speichern können. – zoul

+0

Danke, yeah, ich denke ich versuche nur klar zu machen, welche Möglichkeiten ich für NSNummer –

0

NSNumber s sind unveränderlich und können nur mit einer Factory-Methode oder einer anfänglichen Methode erstellt werden, die ihnen einen numerischen Wert gibt. So weit ich weiß, ist es nicht möglich, mit einer 'leeren' NSNummer zu enden, es sei denn, Sie zählen 0.

0

Es ist sehr üblich (für mich zumindest), ein Objekt aus einem Wörterbuch zu bekommen, erwarte, dass es geht eine NSNummer sein und dann ein Nullobjekt zurückgeben. Wenn dies geschieht und Sie einen intValue-Wert eingeben, wird der Absturz ausgeführt.

Was ich mache, ist Setup-Nullschutz, weil ich lieber einen Standardwert als einen Absturz erhalten würde.

Eine Möglichkeit ist:

-(int) intForDictionary:(NSDictionary *)thisDict objectForKey: (NSString *)thisKey withDefault: (int)defaultValue 
{ 
    NSNumber *thisNumber = [thisDict objectForKey:thisKey]; 
    if (thisNumber == nil) { 
     return defaultValue; 
    } 
    return [thisNumber intValue]; 
} 

Und ich habe ein, wie es nur für Schwimmer. Dann erhalten Sie zumindest Ihren Standardwert. Eine weitere Möglichkeit ist es, nur ein Verfahren zum Schutz nil erstellen ..

-(NSNumber *)nilProtectionForNumber: (NSNumber *)thisNumber withDefault: (NSNumber *)defaultNumber 
{ 
    if (thisNumber) { 
     return thisNumber; 
    } 
    else 
     return defaultNumber; 
} 

Dass man Sie so nennen würden:

NSNumber *value = [self nilProtectionForNumber:[dict objectForKey:keyThatShouldBeNSNumber] withDefault:[NSNumber numberWithInt:0]]; 
0

Umgang mit Swift 2.0 und Parsen:

var myNumber = yourArray!.objectForKey("yourColumnTitle") 
    if (myNumber == nil) { 
    myNumber = 0 
     } 

In meinem Fall musste ich dann:

let myNumberIntValue = myNumber!.intValue