2010-09-15 16 views
18

Jak sprawdzić, czy obiekt NSNumber jest zerowy lub pusty?Sprawdź, czy numer NSN jest pusty

OK nil jest proste:

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

Ale jeśli obiekt został utworzony, ale nie ma w niej wartość, bo zadanie nie powiodło się, w jaki sposób mogę to sprawdzić? Użyj czegoś takiego?

if ([myNumber intValue]==0) 
    doSomething 

Czy istnieje ogólna metoda testowania przedmiotów na pustki jak na NSString dostępnych (zobacz ten post)?

Przykład 1

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

których wartość nie emptyNumber zawierać? Jak mogę sprawdzić, czy emptyNumber jest pusty?

Przykład 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; 

Co się stanie, jeśli mogę użyć tego po emptyNumber został ustawiony na zero?

[emptyNumber intValue] 

Czy otrzymam zero?

Przykład 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!"); 

Jak ten sposób NSLog nigdy nie jest wywoływana. myEmptyValue nie jest nil, a nie NSNull. Czy zawiera on dowolną liczbę?

+0

@ [0.7] da NSNumber to zdecydowanie nie zero, ale intValue zwróci 0. To jest zły test. – gnasher729

+0

Wzniesiono ze względu na wielkie szczegóły, które pomogły wyjaśnić coś, z czym mam do czynienia od domyślnych. NSNumber * savedPin = [[NSUserDefaults standardUserDefaults] valueForKey: @ "someKey"]; zwraca obiekt, który ma klasę __NSCFConstantString i tym samym nie udało się porównać z zerą. DZIĘKI! –

Odpowiedz

12

NSValue, NSNumber, ... mają być tworzone z wartości i zawsze je mieć. Testowanie pod kątem określonej wartości, takiej jak 0, działa tylko wtedy, gdy nie znajduje się w zakresie prawidłowych wartości, z którymi pracujesz.

W rzadkim przypadku, gdy kod jest bardziej prosta do pracy, jeśli mają wartość, która reprezentuje „nieważny” lub „nie ustawiono” i nie można wykorzystać nil (np standardowych pojemnikach) możesz użyć zamiast tego NSNull.

W swojej pierwszym przykładzie może to być:

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

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

jednak pamiętać, że można po prostu nie włożyć (lub usunąć) tę wartość, chyba że trzeba odróżnić nil (czyli nie w pojemniku), a powiedzieć "nieważny":

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

w odniesieniu do drugiego przykładu, -intValue dać s ty 0 - ale po prostu dlatego, że wysyłanie wiadomości do nil zwraca 0. Możesz również uzyskać 0 np. dla NSNumber, którego intValue został wcześniej ustawiony na 0, co może być prawidłową wartością.
Jak już napisałem powyżej, możesz zrobić tylko coś takiego, jeśli 0nie jest prawidłową wartością dla ciebie. Uwaga: dla ciebie, co działa najlepiej całkowicie zależy od Twoich wymagań.

Pozwól mi spróbować podsumować:

Wariant nr 1:

Jeśli nie potrzebujesz wszystkich wartości z zakresu liczb, można użyć jednego lub -1 (0 lub .. .) i -intValue/... specjalnie oznaczające "puste". Najwyraźniej tak nie jest w twoim przypadku.

Wariant nr 2:

Po prostu nie przechowywać lub usunąć wartości z pojemnika, jeśli są one „pusta”:

// 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 
} 

jednak oznacza to, że nie jest różnica między kluczami, które są puste, a kluczami, które nigdy nie istnieją lub są nielegalne.

Opcja nr 3:

W niektórych rzadkich przypadkach jej wygodniej trzymać wszystkie klucze w słowniku i reprezentują „pusta” z inną wartością. Jeśli nie można skorzystać z jednej z zakresu numerów musimy umieścić coś inaczej jak NSNumber nie mają pojęcia „pusty”. Kakao ma już NSNull takich przypadkach:

// 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; 
    // ... 
} 

Opcja ta umożliwia teraz rozróżnić „pusta”, „nie jest pusta” i „nie w kontenerze” (np nielegalne Key).

+0

Edytowałem mój wpis. Jak mogę sprawdzić pustkę w tym "specjalnym przypadku"? Czy znajduje się on w zakresie prawidłowych wartości? – testing

+0

Wstawiasz '[NSNull null]', aby przetestować później obiekt NSNumber na pustce. OK, ale jakie są standardowe pojemniki? Nie mogę zagwarantować, która wartość jest przypisana do mojego obiektu NSNumber. Więc nie wiem, kiedy wstawić 'nil' lub' NSNull'. W moim przykładzie może to być również pusty ciąg.Czy powinienem najpierw przetestować zwracaną wartość 'objectForKey', jeśli jest to pusty ciąg, a następnie powinienem wstawić' nil' lub 'NSNull' w moim obiekcie NSNumber? Myślę, że zawsze powinienem wstawić zero, chyba że potrzebuję NSNull dla jakiegoś przypadku. Zobacz mój drugi przykład. – testing

+1

@ testowanie: Standardowymi kontenerami są te z Cocoa Touch ('NSArray',' NSDictionary', ...). Pierwsze próbki testują obiekt będący 'NSNull', drugi zakłada * nie wstawiasz wartości do kontenera * - nie możesz wstawić' nil' w tych, 'nil' oznacza *" nie w kontenerze " *. Po prostu musisz zdecydować, czy musisz rozróżnić * "nieważne" */* "nie istnieje" * i * "nie w kontenerze" *. Twoje ostatnie zdanie jest bliskie temu, co powiem - albo nie umieszczaj go w kontenerze (otrzymujesz 'nil' dla' -objectForKey: ... ') lub używasz' NSNull'. –

3

NSNumber jest albo nil, albo zawiera liczbę, nic pomiędzy. "Pustka" jest pojęciem, które zależy od semantyki danego obiektu i dlatego nie ma sensu szukać ogólnego sprawdzenia pustki.

Jak dla swoich przykładach, istnieje kilka rzeczy dzieje:

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

NSLog wypisze 0 tutaj, ale tylko dlatego, że jest to metoda w NSStringintValue. Jeżeli zmienisz wiadomość do czegoś, co tylko NSNumber może zrobić, kod zawiedzie:

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

Ten rzuci:

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

Czyli jesteś nie coraz pewne ogólne „pusty” wartości wracając z hasha, po prostu przechowujesz tam zapisaną NSString.

Po pustym (== nil) NSNumber i wysłaniu komunikatu wynik będzie wynosił zero.To po prostu konwencja język, który upraszcza kod:

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

zamieni się w ten sposób:

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

Nadzieja to pomaga.

+0

Co robi NSNumber * test = [NSNull null]? –

+1

Jak napisano, ten kod nie ma większego sensu. NSNull jest po prostu "obiektową wersją zerowej wartości" i jedynym powodem, dla którego istnieje, jest reprezentowanie "pustej" wartości w kolekcjach, które nie mogą bezpośrednio przechowywać zero. – zoul

+0

Dzięki, tak, myślę, że po prostu staram się wyjaśnić dokładnie, jaki zakres możliwości muszę wziąć pod uwagę dla NSNumber –

0

NSNumber s są niezmienne i mogą być tworzone tylko z jednej metody fabrycznej lub początkowego sposobu, który daje im pewną wartość liczbową. O ile mi wiadomo, nie jest możliwe uzyskanie "pustego" numeru NSN, chyba że policzysz 0.

0

To bardzo często (przynajmniej dla mnie), aby uzyskać obiekt ze słownika, spodziewać się, że idzie być NSNumber, a następnie zwrócić mu obiekt zerowy. Jeśli tak się stanie i zrobisz intame, ulegnie awarii.

Co mogę zrobić, to konfiguracja ochrona nil bo wolałbym uzyskać wartość domyślną niż katastrofie.

Jednym ze sposobów jest:

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

I mam jedną jak i to dla pływaków. Wtedy przynajmniej otrzymasz swoją domyślną wartość. Innym sposobem jest po prostu stworzyć metodę ochrony zera ..

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

że jeden chcesz nazwać tak:

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

czynienia z Swift 2.0 i składni:

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

W moim przypadku musiałem wtedy:

let myNumberIntValue = myNumber!.intValue