Який правильний спосіб перевірити наявність нульового рядка в Objective-C?


184

Я використовував це в додатку для iPhone

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

але це викидає якийсь виняток, і на консолі видно, що заголовок "(null)".

Тому я зараз це використовую:

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

У чому різниця, і який найкращий спосіб визначити, чи є рядок нульовим?


Відповіді:


395

Як зазначали інші, існує багато видів "нуля" під какао / мета С. Але ще одне, що слід зазначити, - це те, що [назва isKindOfClass: [клас NSNull]] безглуздо складна, оскільки [NSNull null] документально підтверджено синглтон, тож ви можете просто перевірити рівність вказівника. Див. Теми для какао: використання нуля .

Тож хорошим випробуванням може бути:

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

Зверніть увагу, як ви можете використати той факт, що навіть якщо заголовок є нульовим, title.length поверне 0 / nil / false, тобто 0 в цьому випадку, тому вам не потрібно це робити окремо. Це те, до чого люди, які не знайомі з Ціллю C, мають проблеми з звиканням, особливо з інших мов, де повідомлення / метод закликає до краху.


Дякую! Однак я задав це питання в першу чергу, тому що я отримував виняток, оскільки "назва" недійсна.
Тео Чонг Пінг

1
Якого типу має бути назва? Наприклад, якщо мова йде про NSString, я отримую таке попередження: порівняння різних типів Objective-C "struct NSNull *" та "struct NSString *" не має атрибуту це питання було задано)?
thebossman

1
Служить мені правильним для розміщення коду без його компіляції ;-). title, ймовірно, є NSString, але незалежно від типу заголовка, просто наведіть null на загальний тип id: (id) [NSNull null].
Пітер Н Льюїс

1
@JLT nil і [NSNull null] ніколи не будуть однаковими. [NSNull null] - це однотонний об'єкт, який може бути використаний як stand-in для нуля, коли nil не може бути використаний (наприклад, у значенні NSArray або NSDictionary). Таким чином, випадок використання може бути там, де у вас був NSArray необов'язкових рядків, деякі з яких можуть бути нульовими, і ви використовуєте [NSNull null] в масиві для випадків null. На практиці тест рідко потрібен, лише коли ви (або бібліотека, яку ви використовуєте!) Активно використовуєте [NSNull null] як заповнювач.
Пітер Н Льюїс

1
Приїжджаючи сюди з Flutter і шукаючи причину, чому Mapзначення предмета - яке знаходиться nullв Дартсі - не відповідає nilабо NULLв цілі C. Причиною було те, що воно є насправді NUNull null, а не NULLнульовим. Дякую @PeterNLewis!
Олександр

25

це так само просто

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

пам'ятайте, що в об'єкті C, якщо об'єкт є нульовим, він повертає 0 як значення.

Це дозволить отримати нульову рядок і рядок довжиною 0.


49
Це не спрацює, якщо об’єктом є NSNull, все-таки потрібно спочатку чітко перевірити це.
Джеремі Мак

6
ви також можете зробити категорію для NSNull, щоб вона повернула 0 до повідомлення про довжину :)
Mihai Timar

1
Так, це вийде з ладу, якщо об'єктом є NSNull.
Майк Гледхілл

Це буде вилітати , якщо об'єкт дорівнює NSNull
Joan

1
На додаток до нерозпізнаної селекторної проблеми NSNull, це не буде відрізняти між NSString покажчиком, який є нульовим, або NSString, який є насправді, але по суті є порожнім рядком. (Наприклад, як буквальний object = @"";або object = nil;)
KellyTheDude

6

Дивіться наступні пов’язані статті на цьому веб-сайті:

Я думаю, що ваша помилка пов’язана з чимось іншим, тому що вам не потрібно робити зайву перевірку.

Також дивіться це пов’язане питання: Правильна перевірка текстового стовпця nil sqlite


Прикро мені не вистачає «точок» , щоб додати другу гіперпосилання (навіть що - то на цьому сайті) Дивись також: - stackoverflow.com/questions/598396 / ...
Тіммі

...Дозвольте. Хоча ви маєте змогу редагувати власні повідомлення від реп. 0.
Рог

Спасибі - це було дуже ласкаво. Коли я писав свій початковий пост, він сказав, що щось на зразок нових користувачів може додати лише 1 гіперпосилання (що здається трохи суворим - особливо це стосується перехресних посилань на цьому сайті).
TimM

6

Я виявив, що для того, щоб реально це зробити правильно, вам в кінцевому підсумку потрібно зробити щось подібне

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

Інакше у вас виникають дивні ситуації, коли контроль все одно обійде ваш чек. Я не натрапив на той, який робить його минулим isEqualі перевірки довжини.


5

Що з усіма цими "роботами для мене відповідає"? Всі ми кодуємо однією мовою, і правила є

  1. Переконайтеся, що посилання не є нульовим
  2. Перевірте і переконайтесь, що довжина рядка не дорівнює 0

Саме це буде працювати для всіх. Якщо дане рішення "працює для вас", це лише тому, що потік вашої програми не дозволить створити сценарій, коли посилання може бути нульовим або довжина рядка дорівнює 0. Правильний спосіб зробити це метод, який буде обробляти чого ти хочеш у всіх випадках.


4
Якщо посилання є nil(зауважте: не "null"), то надсилання повідомлення, наприклад length, призведе до 0 (або відповідного 0-значення для типу повернення методу). Це правило мови. У nilцьому випадку не потрібно перевіряти окремо.
jscs

Я сказав нульовим просто через звички C ++, і якщо ваш код викликає методи на об’єктах, що не мають нуля, ймовірно, ваш код порушений. Ви побачите, що методи виклику на NULL / NIL (та сама концепція), як правило, є поганою ідеєю на будь-якій мові. Тільки тому, що obj-c дозволяє робити щось подібне, це не означає, що ви повинні просто обходити нульові об'єкти і намагатися використовувати їх без турботи.
ненчев

1
Довжина надсилання до нуля робить 0 - АЛЕ довжина відправки в NSNull створює виняток.
cdstamper

@nenchev Ніхто нічого не говорить про просто перенесення нульових об'єктів, але перевірка нуля, потім виклик методу та використання його зворотного значення є ІМО гірше, ніж використання мовної функції, як це призначено для використання та перевірки дійсності повернення значення методу згодом.
Кевін

@Kevin Я не впевнений, наскільки це гірше насправді, лише тому, що мовна особливість не означає його велику. Не перевіряючи, чи може його нуль відкрити шлях коду, що може призвести до більш важкої помилки виконання помилки. Зазвичай найкраще переконатися, що ваші вклади такі, як ви очікували, і реагувати відповідно, якщо вони не є. Мені особисто не подобається "особливість" не отримувати виключень під час запуску при спробі надіслати повідомлення об'єкту "нульовий", оскільки це часто полегшує пропущення деяких помилок виконання.
ненчев

4

Якщо ви хочете протестувати проти всіх нульових / порожніх об'єктів (наприклад, порожніх рядків або порожніх масивів / наборів), ви можете скористатися наступним:

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
Це насправді не перевіряє предмет == [NSNull null], що, ймовірно, має сенс.
Пітер Н Льюїс

3

Є дві ситуації:

Можливо, що об’єкт є [NSNull null], або це неможливо.
Ваша програма, як правило, не повинна використовувати [NSNull null];вас, лише якщо ви хочете помістити " null " об'єкт у масив або використовувати його як значення словника. І тоді ви повинні знати, які масиви чи словники можуть містити нульові значення, а які - ні.
Якщо ви думаєте, що масив ніколи не містить [NSNull null]значень, то не перевіряйте його. Якщо є[NSNull null] , ви можете отримати виняток, але це нормально: винятки Objective-C вказують на помилки програмування. У вас є помилка програмування, яку потрібно виправити, змінивши якийсь код.

Якщо об’єкт міг бути [NSNull null], то ви перевіряєте це досить просто шляхом тестування
(object == [NSNull null]). Виклик isEqualабо перевірка класу об’єкта - це нісенітниця. Є лише один [NSNull null]об’єкт, і звичайний старий оператор C перевіряє його на то, що він відповідає найпростішим та найефективнішим способом.

Якщо ви перевіряєте NSStringоб'єкт, який не може бути [NSNull null](тому що ви знаєте, що цього не може бути [NSNull null]або тому, що ви просто перевірили, чи він відрізняється від [NSNull null], тоді вам потрібно запитати себе, як ви хочете обробити порожню рядок, що дорівнює довжині 0. Якщо ви трактувати це як nullрядок nil, тоді тестуйте (object.length == 0)object.length поверне 0, якщо object == nilцей тест охоплює нульові об'єкти та рядки довжиною 0. Якщо ви обробляєте рядок довжиною 0, відмінний від нульової рядка, просто перевірте, чи є object == nil.

Нарешті, якщо ви хочете додати рядок до масиву чи словника, а рядок може бути нульовим, у вас є вибір не додавати його, а замінювати його @""чи замінювати його [NSNull null]. Замінивши його @""означає, що ви втрачаєте здатність розрізняти "немає рядка" і "рядок довжиною 0". Замінивши його [NSNull null]означає, що вам потрібно писати код під час доступу до масиву чи словника, який перевіряє наявність [NSNull null]об'єктів.


Дуже довго, але це добре. NSNull повинен ПРИЄДНАЙТЕ ТІЛЬКИ в СІНГЛЕТОНІ! Це все питання не має сенсу, говорить мені, що кодер не робив щось правильне, і багато іншого в майбутньому також не читав посібник / хороша практика кодування
Stephen J

2

Ви просто перевірите наявність нуля

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

або

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

2

Рішення MACRO (2020)

Ось макрос, який я використовую для безпечного рядка замість отримання рядка " (null) " на UILabel, наприклад:

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

скажімо, у вас є власність класу-члена та ім’я, а ім’я - нульове:

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

з макросом:

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

приємно і чисто 😊

Розширення рішення (2020)

Якщо ви хочете перевірити нульовий і порожній рядок у своєму проекті, ви можете використовувати мій рядок розширення нижче:

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 + Розширення.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;
}

Приклад використання

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");
}

Це буде працювати в таких випадках, NSString *strOne = @""АБО NSString *strOne = @"StackOverflow"АБО NSString *strOne = [NSNull null]АБО NSString *strOne.


0

Якщо подібного не існує, ви можете створити категорію NSString:

@interface NSString (TrucBiduleChoseAdditions)

- (BOOL)isEmpty;

@end

@implementation NSString (TrucBiduleChoseAdditions)

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

@end

Це, мабуть, надмірно, і я не думаю, що це вирішить цю проблему.
Рог

9
Self == nil є безглуздим - якби self був нульовим, ціль C не закликала б вас в першу чергу. [(NSString *) nil isEmpty] просто поверне 0 / nil / false, не називаючи свого коду.
Пітер Н Льюїс

4
Насправді, після цього [(NSString *) nil isEmpty] поверне помилкове значення. Під час написання таких методів Objective C краще визначити їх так, щоб нульові значення 0 / nil / false мали сенс, тому писати метод як hasCharacters було б краще. Зауважте, що довжина вже працює для цього, оскільки ви можете використовувати, якщо (s.length) будь-де ви хочете використовувати, якщо (! S.isEmpty) і s.length правильно повернуть 0 для випадку s == nil.
Пітер Н Льюїс

Це серйозна аварія. Ви реалізували "isEmpty" для NSString, але якщо це насправді NSNull, то isEmpty буде надісланий до NSNull, і він завершиться збоєм, оскільки він не відповідає на це повідомлення!
daniel.gindi

0

Що для мене працює if ( !myobject )


3
Це не працює для нульових об'єктів, лише для нульових об'єктів. Наприклад ... 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"); }
Рік Сміт-Унна

Помилка .. вибачте за форматування, але код буде скомпільований :)
Рік Сміт-Унна

0

Повна перевірка рядка на нульові умови може бути наступною: <\ br>

    якщо (містінг)
     {
       if ([mystring isEqualToString: @ ""])
        {
          mystring = @ "деяка рядок";
        }
     }    
    ще
     {
        // заяви
     }


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

1
Хоча цей фрагмент коду може відповісти на запитання, він не містить жодного контексту, щоб пояснити, як і чому. Подумайте про додавання речення чи двох, щоб пояснити свою відповідь.
фірмовий сценарій

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

0

Для рядка:

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

}

Перегляньте малюнок нижче:

введіть тут опис зображення


0

Для рядка:

+ (BOOL) checkStringIsNotEmpty:(NSString*)string {
if (string == nil || string.length == 0) return NO;
return YES;}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.