Jaki jest właściwy sposób sprawdzania pustego ciągu w Objective-C?


184

Korzystałem z tego w mojej aplikacji na iPhone'a

if (title == nil) {
    // do something
}

ale generuje wyjątek, a konsola pokazuje, że tytuł to „(null)”.

Teraz używam tego:

if (title == nil || [title isKindOfClass:[NSNull class]]) {
    //do something
}

Jaka jest różnica i jaki jest najlepszy sposób ustalenia, czy ciąg znaków ma wartość NULL?


Odpowiedzi:


395

Jak zauważyli inni, w Cocoa / Objective C istnieje wiele rodzajów „null”. Należy jednak zauważyć, że [tytuł to KindOfClass: [klasa NSNull]] jest bezcelowo złożony, ponieważ [NSNull null] jest udokumentowane jako singleton, więc możesz po prostu sprawdzić równość wskaźnika. Zobacz Tematy dotyczące kakao: Korzystanie z Null .

Tak więc dobrym testem może być:

if (title == (id)[NSNull null] || title.length == 0 ) title = @"Something";

Zwróć uwagę, jak możesz wykorzystać fakt, że nawet jeśli tytuł jest zerowy, title.length zwróci 0 / zero / fałsz, tj. 0 w tym przypadku, więc nie musisz specjalnie tego robić. Jest to coś, do czego ludzie, którzy są nowi w Celu C, mają trudności z przyzwyczajeniem się, zwłaszcza pochodzącymi z innych języków, w których komunikaty / metody wywołują awarię zerową.


Dzięki! Jednak zadałem to pytanie przede wszystkim, ponieważ otrzymywałem wyjątek, ponieważ „tytuł” ​​jest pusty.
Teo Choong Ping

1
Jakim typem powinien być tytuł? Jeśli na przykład jest to NSString, pojawia się następujące ostrzeżenie: porównanie różnych typów Objective-C „struct NSNull *” i „struct NSString *” nie ma obsady Czy istnieje jakiś sposób na usunięcie tego (nie wiem, czy to się zmieniło od tego czasu to pytanie zostało zadane)?
thebossman,

1
Służy mi do wysyłania kodu bez kompilacji ;-). tytuł jest prawdopodobnie NSString, ale niezależnie od typu tytułu, po prostu wyrzuć null na ogólny typ identyfikatora: (id) [NSNull null].
Peter N Lewis,

1
@JLT zero i [NSNull null] nigdy nie będą takie same. [NSNull null] to obiekt typu singleton, który może być używany jako stand-in dla zera, gdy zero nie może być użyte (np. W wartości NSArray lub NSDictionary). Zatem przypadkiem użycia może być miejsce, w którym macie tablicę NSA opcjonalnych ciągów, z których niektóre mogą mieć wartość null, a macierz [NSNull null] używa się w tablicy dla przypadków null. W praktyce test jest rzadko potrzebny, tylko wtedy, gdy ty (lub biblioteka, której używasz!) Aktywnie używasz [NSNull null] jako symbolu zastępczego.
Peter N Lewis

1
Przybywając tutaj z Fluttera i szukając przyczyny, dla której Mapwartość przedmiotu - która jest nullw Dart - nie odpowiada nilani NULLw Celu C. Powodem było to, że tak naprawdę NUNull nullnie jest NULLzerowa. Dziękuję @PeterNLewis!
Aleksandar

25

to jest tak proste jak

if([object length] >0)
{
  // do something
}

pamiętaj, że w celu C, jeśli obiekt jest pusty, zwraca 0 jako wartość.

Otrzymasz zarówno ciąg zerowy, jak i ciąg o długości 0.


49
To nie zadziała, jeśli obiekt ma wartość NSNull, ale najpierw trzeba to wyraźnie sprawdzić.
Jeremy Mack

6
możesz także utworzyć kategorię dla NSNull, aby zwracała 0 do wiadomości o długości :)
Mihai Timar

1
Tak, spowoduje to awarię, jeśli obiektem jest NSNull.
Mike Gledhill

Spowoduje to awarię, jeśli obiekt jest równy NSNull
joan

1
Oprócz nierozpoznanego problemu z selektorem NSNull, nie rozróżnia to wskaźnika NSString, który jest zero, lub NSString, który faktycznie istnieje, ale jest zasadniczo pustym ciągiem. (Na przykład jako dosłowny object = @"";lub object = nil;)
KellyTheDude

6

Zapoznaj się z następującymi powiązanymi artykułami na tej stronie:

Myślę, że twój błąd jest związany z czymś innym, ponieważ nie musisz wykonywać dodatkowej kontroli.

Zobacz także powiązane pytanie: Właściwe sprawdzenie kolumny tekstowej nil sqlite


Irytujące nie mam wystarczającej liczby „punktów”, aby dodać drugie hiperłącze (nawet do czegoś na tej stronie) patrz także: - stackoverflow.com/questions/598396/...
TimM

...pozwól mi. Chociaż powinieneś być w stanie edytować własne posty od rep 0.
Rog

Dzięki - to było bardzo miłe. Kiedy napisałem swój pierwszy post, powiedziano, że nowi użytkownicy mogą dodać tylko 1 hiperłącze (co wydaje się nieco trudne - szczególnie w przypadku linków krzyżowych na tej stronie).
TimM,

6

Przekonałem się, że aby naprawdę to zrobić, musisz zrobić coś podobnego

if ( ( ![myString isEqual:[NSNull null]] ) && ( [myString length] != 0 ) ) {
}

W przeciwnym razie zdarzają się dziwne sytuacje, w których kontrola nadal omija czek. Nie natknąłem się na taki, który mija isEquali sprawdza długość.


5

Co z tymi wszystkimi „odpowiedziami dla mnie”? Wszyscy kodujemy w tym samym języku, a zasady są

  1. Upewnij się, że referencja nie jest równa zero
  2. Sprawdź i upewnij się, że długość łańcucha nie jest równa 0

To będzie działać dla wszystkich. Jeśli dane rozwiązanie „działa tylko dla Ciebie”, to tylko dlatego, że przepływ aplikacji nie zezwala na scenariusz, w którym odwołanie może mieć wartość NULL lub długość łańcucha powinna wynosić 0. Właściwym sposobem na to jest metoda, która będzie obsługiwać co chcesz we wszystkich przypadkach.


4
Jeśli referencja to nil(uwaga: nie „null”), wówczas wysłanie wiadomości, podobnie jak length, spowoduje wygenerowanie 0 (lub odpowiedniej wartości 0 dla typu zwracanego przez metodę). To jest reguła języka. W niltym przypadku nie trzeba sprawdzać osobno.
jscs

Powiedziałem null po prostu z powodu nawyków C ++, a jeśli twój kod wywołuje metody na obiektach zerowych, istnieje prawdopodobieństwo, że kod jest zepsuty. Przekonasz się, że wywoływanie metod na NULL / NIL (ta sama koncepcja) jest ogólnie złym pomysłem w każdym języku. Tylko dlatego, że obj-c pozwala ci robić coś takiego, nie oznacza, że ​​powinieneś po prostu omijać zero obiektów i próbować używać ich bez opieki.
nenchev

1
Wysyłanie długości do zera powoduje 0 - ALE wysyłanie długości do NSNull powoduje wyjątek.
cdstamper

@nenchev Nikt nic nie mówi o przekazywaniu obiektów zerowych, ale sprawdzanie zeru, a następnie wywoływanie metody i używanie jej wartości zwracanej jest IMO gorsze niż używanie funkcji języka, takiej jak ma być używana, i sprawdzanie poprawności wartości zwracanej metody później.
Kevin

@Kevin Nie jestem pewien, jak naprawdę jest gorzej, tylko dlatego, że funkcja języka nie oznacza, że ​​jest świetny. Nie sprawdzanie, czy wartość null może otworzyć ścieżkę kodu, co może prowadzić do trudniejszego do śledzenia błędu czasu wykonywania. Zazwyczaj najlepiej jest sprawdzić, czy dane wejściowe są zgodne z oczekiwaniami i odpowiednio zareagować, jeśli nie są. Osobiście nie podoba mi się „funkcja” polegająca na tym, że nie otrzymuję wyjątków w czasie wykonywania, gdy próbuję wysłać wiadomość do zerowego obiektu, ponieważ często ułatwia to pominięcie niektórych błędów środowiska wykonawczego.
nenchev

4

Jeśli chcesz przetestować na wszystkich zerowych / pustych obiektach (takich jak puste łańcuchy lub puste tablice / zestawy), możesz użyć następujących opcji:

static inline BOOL IsEmpty(id object) {
    return object == nil
        || ([object respondsToSelector:@selector(length)]
        && [(NSData *) object length] == 0)
        || ([object respondsToSelector:@selector(count)]
        && [(NSArray *) object count] == 0);
}

2
To tak naprawdę nie sprawdza obiektu == [NSNull null], co prawdopodobnie miałoby sens.
Peter N Lewis,

3

Istnieją dwie sytuacje:

Możliwe, że obiekt jest [NSNull null]lub jest to niemożliwe.
Twoja aplikacja zwykle nie powinna z [NSNull null];ciebie korzystać , używaj jej tylko, jeśli chcesz umieścić w tablicy obiekt „ zerowy ” lub użyć go jako wartości słownikowej. A potem powinieneś wiedzieć, które tablice lub słowniki mogą zawierać wartości zerowe, a które nie.
Jeśli uważasz, że tablica nigdy nie zawiera [NSNull null]wartości, nie sprawdzaj jej. Jeśli istnieje [NSNull null], możesz otrzymać wyjątek, ale to jest w porządku: wyjątki Objective-C wskazują na błędy programowania. I masz błąd programowania, który wymaga naprawy poprzez zmianę kodu.

Jeśli obiekt może być [NSNull null], to sprawdzasz to po prostu przez testowanie
(object == [NSNull null]). Wywołanie isEquallub sprawdzenie klasy obiektu to nonsens. Jest tylko jeden [NSNull null]obiekt, a zwykły stary operator C sprawdza go w jak najprostszy i najbardziej wydajny sposób.

Jeśli NSStringzaznaczysz obiekt, który nie może być [NSNull null](ponieważ wiesz, że nie może być [NSNull null]lub ponieważ właśnie sprawdziłeś, że jest inny niż) [NSNull null], musisz zadać sobie pytanie, jak traktować pusty ciąg znaków, czyli taki o długości 0. traktuj to nulljak łańcuch nil, a następnie przetestuj (object.length == 0). object.length zwróci 0 jeśli object == nil, więc ten test obejmuje zero obiektów i łańcuchów o długości 0. Jeśli traktujesz łańcuch o długości 0 różnej od zera, po prostu sprawdź, czy object == nil.

Wreszcie, jeśli chcesz dodać ciąg do tablicy lub słownika, a ciąg może być zerowy, możesz nie dodawać go, zamieniać go na @""lub zamieniać na [NSNull null]. Zastąpienie go @""oznacza utratę możliwości odróżnienia „bez ciągu” od „ciągu o długości 0”. Zastąpienie go [NSNull null]oznacza, że ​​musisz pisać kod podczas uzyskiwania dostępu do tablicy lub słownika, który sprawdza [NSNull null]obiekty.


Bardzo długo, ale to dobrze. NSNull powinien pojawiać się TYLKO W SINGLETONACH! To całe pytanie nie ma sensu, mówi mi, że programista nie zrobił czegoś poprawnego, a wiele innych w przyszłości również nie przeczytało instrukcji obsługi / dobrej praktyki kodowania
Stephen J

2

Po prostu sprawdź zero

if(data[@"Bonds"]==nil){
  NSLog(@"it is nil");
}

lub

if ([data[@"Bonds"] isKindOfClass:[NSNull class]]) {
    NSLog(@"it is null");
}

2

Rozwiązanie MACRO (2020)

Oto makro, którego używam do bezpiecznego ciągu zamiast pobierania na przykład ciągu „ (null) ” na UILabel :

#define SafeString(STRING) ([STRING length] == 0 ? @"" : STRING)

powiedzmy, że masz klasę członkowską i właściwość name, a nazwa to zero:

NSLog(@"%@", member.name); // prints (null) on UILabel

z makro:

NSLog(@"%@", SafeString(member.name)); // prints empty string on UILabel

ładne i czyste 😊

Rozwiązanie przedłużające (2020)

Jeśli wolisz sprawdzić zero i pusty ciąg w swoim projekcie, możesz użyć mojej linii pomocniczej poniżej:

NSString + Extension.h

///
/// Checks if giving String is an empty string or a nil object or a Null.
/// @param string string value to check.
///
+ (BOOL)isNullOrEmpty:(NSString*)string;

NSString + Extension.m

+ (BOOL)isNullOrEmpty:(NSString*)string {
    if (string) { // is not Nil
        NSRange range = [string rangeOfString:string];
        BOOL isEmpty = (range.length <= 0 || [string isEqualToString:@" "]);
        BOOL isNull = string == (id)[NSNull null];

        return (isNull || isEmpty);
    }

    return YES;
}

Przykładowe użycie

if (![NSString isNullOrEmpty:someTitle]) {
    // You can safely use on a Label or even add in an Array for example. Remember: Arrays don't like the nil values!
}



1
@interface NSString (StringFunctions)
- (BOOL) hasCharacters;
@end

@implementation NSString (StringFunctions)
- (BOOL) hasCharacters {
    if(self == (id)[NSNull null]) {
        return NO;
    }else {
        if([self length] == 0) {
            return NO;
        }
    }
    return YES;
}
@end

NSString *strOne = nil;
if([strOne hasCharacters]) {
    NSLog(@"%@",strOne);
}else {
    NSLog(@"String is Empty");
}

To działałoby w następujących przypadkach: NSString *strOne = @""LUB NSString *strOne = @"StackOverflow"LUB NSString *strOne = [NSNull null]LUB NSString *strOne.


0

Jeśli tego typu rzeczy jeszcze nie istnieją, możesz utworzyć kategorię NSString:

@interface NSString (TrucBiduleChoseAdditions)

- (BOOL)isEmpty;

@end

@implementation NSString (TrucBiduleChoseAdditions)

- (BOOL)isEmpty {
    return self == nil || [@"" isEqualToString:self];
}

@end

To chyba przesada i nie sądzę, że rozwiąże ten problem.
Rog

9
Jaźń == zero jest bezcelowe - gdyby jaźń było zero, Cel C nie zadzwoniłby do ciebie w pierwszej kolejności. [(NSString *) zero isEmpty] zwróci po prostu 0 / zero / false bez wywoływania twojego kodu.
Peter N Lewis,

4
W rzeczywistości, [(NSString *) zero isEmpty] zwróci false. Pisząc takie metody Celu C, lepiej je zdefiniować, aby zero 0 / zero / fałsz miało sens, więc pisanie metody jako hasCharacters byłoby lepsze. Zauważ, że długość już do tego służy, ponieważ możesz użyć if (s.length) w dowolnym miejscu, w którym chcesz użyć if (! S.isEmpty) i s.length poprawnie zwróci 0 w przypadku s == zero.
Peter N Lewis,

To poważna awaria. Zaimplementowałeś „isEmpty” dla NSString, ale jeśli faktycznie jest to NSNull, to isEmpty zostanie wysłany do NSNull i ulegnie awarii, ponieważ nie odpowiada na ten komunikat!
daniel.gindi

0

Dla mnie działa if ( !myobject )


3
To nie działa dla zerowych obiektów, tylko zerowe obiekty. Na przykład ... NSArray *testarray = [NSArray arrayWithObjects:[NSNull null],@"", nil]; NSString *string = [testarray objectAtIndex:0]; NSLog(@"null string value: %@",string); if (!string) { NSLog(@"string evaluates to null"); } if (string && (string==(id)[NSNull null])) { NSLog(@"string does not evaluate to null"); }
Rik Smith-Unna

Err .. przepraszam za formatowanie, ale kod się skompiluje :)
Rik Smith-Unna

0

Pełne sprawdzenie ciągu pod kątem warunków zerowych może wyglądać następująco: <\ br>

    jeśli (tajemnica)
     {
       if ([mystring isEqualToString: @ ""])
        {
          mystring = @ "some string";
        }
     }    
    jeszcze
     {
        //sprawozdania
     }

0

Sprawdzam tylko ciąg zerowy za pomocą

if ([myString isEqual: [NSNull null]])


0
if ([linkedStr isEqual:(id)[NSNull null]])
                {
                    _linkedinLbl.text=@"No";
                }else{
                    _linkedinLbl.text=@"Yes";
                }

1
Ten fragment kodu może odpowiedzieć na pytanie, ale nie zawiera kontekstu wyjaśniającego, w jaki sposób i dlaczego. Rozważ dodanie zdania lub dwóch w celu wyjaśnienia swojej odpowiedzi.
brandonscript

0
if ([strpass isEqual:[NSNull null]] || strpass==nil || [strpass isEqualToString:@"<null>"] || [strpass isEqualToString:@"(null)"] || strpass.length==0 || [strpass isEqualToString:@""])
{
    //string is blank  
}

0

Dla ciągu:

+ (BOOL) checkStringIsNotEmpty:(NSString*)string {
if (string == nil || string.length == 0) return NO;
return YES;

}

Zobacz zdjęcie poniżej:

wprowadź opis zdjęcia tutaj


0

Dla ciągu:

+ (BOOL) checkStringIsNotEmpty:(NSString*)string {
if (string == nil || string.length == 0) return NO;
return YES;}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.