Строка isNullOrEmpty как категория

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

Я использую этот код на основе ответов в эта тема:

@implementation NSString (NSStringExtension)
- (BOOL)isNullOrEmpty {
    return self == nil || 
    self == (id)[NSNull null] ||
    [@"" isEqualToString:self] || 
    [[self stringByReplacingOccurrencesOfString:@" " withString:@""] length] == 0||
    [self isEqualToString:@"(null)"]
     || ([self respondsToSelector:@selector(length)] && [(NSData *) self length] == 0)
     || ([self respondsToSelector:@selector(count)] && [(NSArray *) self count] == 0)
     || [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] == 0;
}
@end

Тем не менее, когда я пытаюсь использовать это, я получаю следующее:

NSLog([@"" isNullOrEmpty] ? @"1":@"0"); // prints 1
NSString *s1 = nil;
NSLog([s1 isNullOrEmpty] ? @"1":@"0"); // prints 0
NSLog([args.itemName isNullOrEmpty] ? @"1":@"0"); // prints 0
NSLog([(NSString*)nil isNullOrEmpty] ? @"1":@"0"); // prints 0

Это сбивает меня с толку, и я могу только предположить, что некоторая комбинация iOS5 / ARC приводит к принуждению объекта nil к пустой строке / указателю. Отладчик показывает строку как 0x0, но когда я использую свой метод isNullOrEmpty, я получаю false.


person Echilon    schedule 14.03.2012    source источник


Ответы (9)


return self == nil

Этого никогда не может быть. Если вы попытаетесь отправить isNullOrEmpty (или любое другое сообщение) на nil, ничего не произойдет (objc_msgSend(), функция, отвечающая за отправку сообщений, проверяет получение nil получателя как одно из первых действий и прерывается).

self == (id)[NSNull null]

Этого тоже никогда не будет. Если вы отправите isNullOrEmpty объекту, являющемуся экземпляром NSNull, ваш метод здесь, который является методом на NSString, не будет вызван. Вместо этого будет версия NSNull (которая, вероятно, не существует).

Точно так же ([self respondsToSelector:@selector(count)] && [(NSArray *) self count]) никогда не произойдет. Если объект является NSArray, то isNullOrEmpty никогда не запустится, потому что, опять же, это метод NSString.

Соответственно, [(NSData *) self length] не делает то, что вы думаете. NSString экземпляров действительно отвечают на length, но при приведении объекта к NSData не используется NSData версия метода - он все равно остается NSString версией length, потому что объект на самом деле является значением NSString (приведение типов выполняется только во время компиляции; во время выполнения он ничего не может изменить).

[self isEqualToString:@"(null)"]

Здесь вы, кажется, снова проверяете nil, но вас вводит в заблуждение представление, которое NSLog выбирает при печати nil:

NSLog(@"%@", nil);

В консоли отображается (null), но это не означает, что сам объект представляет собой строку с этими символами. NSLog просто выбирает эту строку для отображения для _30 _. *

Некоторые из ваших действий потребуют, чтобы этот объект находился в категории на NSObject, чтобы метод действительно вызывался, даже если объект не был NSString.

Чтобы проверить строку, состоящую только из пробелов, все, что вам нужно, это сравнение с пустой строкой @"" после обрезки пробелов:

NSString * trimmedSelf = [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
// Then either:
[trimmedSelf isEqualToString:@""];
// Or:
([trimmedSelf length] == 0);

* И даже лучше, выполнение NSLog(@"%@", [NSNull null]); отображает <null> (угловые скобки вместо скобок), удивительно сбивая с толку первые несколько раз, с которыми вы сталкиваетесь NSNull.

person jscs    schedule 14.03.2012
comment
Интересный. Кажется, все работает так, как я хочу, мне нужно проверить someString == nil || [someString isNullOrEmpty] - person Echilon; 16.03.2012
comment
@Echilon: Если вы измените семантику isNullOrEmpty и сделаете это isNotEmpty, вы можете сжать это до простого [someString isNotEmpty], поскольку, если someString равно nil, он также вернет 0 / false / NO. - person jscs; 16.03.2012
comment
это плохо ... обрезать, а затем проверить, пустой ли набор? вы должны перебирать каждый символ, и если вы встретите символ, верните false. - person pqsk; 22.03.2013
comment
@pqsk: Не стесняйтесь публиковать свой собственный ответ. Однако мне не нравится звучание вашего решения; вы не можете перебирать NSString напрямую, и вам нужно будет сравнивать каждый символ с набором пробельных символов. Попробуй. Вам нужно будет получить каждый символ из своей строки, а затем вернуть его в строку - пустая трата времени. - person jscs; 23.03.2013
comment
@JoshCaswell Я знаю, что это 2 года спустя, но вы написали то, что я сказал. Очевидно, вы не можете перебирать NSString, поэтому я сказал каждый символ. Зачем вам возвращать его в строку? Как вы сказали, это пустая трата времени, но я никогда не говорил такого. Как я уже сказал, в тот момент, когда есть символ, который не является пустым местом, вы возвращаете false в этот момент. Дело в том, что ваше решение подходит для некоторых строк, но не масштабируется для любых больших строк. - person pqsk; 13.05.2015

Другой подход может заключаться в определении простого макроса.

#define NSStringIsNullOrEmpty(str) ((str==nil) || [(str) isEqualToString:@""])

Это просто и эффективно. Если вам не нравятся макросы, вы всегда можете преобразовать их в вызов функции, не затрагивая остальной код.

-- Обновлять:

@Bryan поднял хороший вопрос. Встроенная функция - отличный вариант. Вот обновленный макрос, который вычисляет str только один раз.

#define NSStringIsNullOrEmpty(str) ({ NSString *_str=(str); ((tmp==nil) || [tmp isEqualToString:@""]);})
person aLevelOfIndirection    schedule 15.03.2012
comment
будьте осторожны, str получите оценку дважды. использовать встроенную функцию намного лучше, чем макрос - person Bryan Chen; 08.01.2014
comment
переменная tmp не определена в этой функции, просто замените tmp на _str. #define NSStringIsNullOrEmpty (str) ({NSString * _str = (str); ((_str == nil) || [_str isEqualToString: @]);}) - person Alexander Selling; 23.06.2020

В Objective-C отправка сообщения в nil всегда будет возвращать 0 (или NO, обнуленную структуру, NULL и т. Д., В зависимости от объявленного типа возврата). Написанный вами метод isNullOrEmpty на самом деле не будет вызываться, когда вы отправляете isNullOrEmpty на nil. См. Принятый ответ на Отправка сообщения на ноль? для получения дополнительной информации.

Возможно, вы могли бы изменить свой метод на isNotNullOrEmpty. Тогда будет иметь смысл возвращаемое значение 0 при отправке isNotNullOrEmpty в nil.

person Mike Mertsock    schedule 14.03.2012

Вы не вызываете свой метод, а отправляете сообщение на ноль.

person unexpectedvalue    schedule 14.03.2012

Это ожидаемое поведение. Вы все-таки отправляете сообщение nil. Таким образом, он возвращает либо nil (или какое-то другое значение 0). Какое короткое замыкание на false, чтобы было напечатано '0' в случаях, показанных ниже:

NSLog([s1 isNullOrEmpty] ? @"1":@"0"); // prints 0
NSLog([(NSString*)nil isNullOrEmpty] ? @"1":@"0"); // prints 0

Вы даже можете подтвердить, что ваше сообщение не вызывается в таких случаях, установив точку останова в вашем новом методе категории.

person Perception    schedule 14.03.2012

Как уже говорили другие, вызов [nil isNullOrEmpty]; на самом деле не запустит ваш метод. Объект nil и есть сам пустой.

В качестве решения я хотел бы сказать, что вы никогда не должны использовать функции из-за того, что вы используете объектно-ориентированный язык.

BOOL IsStringNilOrEmpty(NSString*)str
{
    return str == nil ||
        str == null ||
        [@"" isEqualToString:str] ||
        [[str stringByReplacingOccurrencesOfString:@" " withString:@""] length] == 0||
        [str isEqualToString:@"(null)"]
        || ([str respondsToSelector:@selector(length)] && [(NSData *) str length] == 0)
        || ([str respondsToSelector:@selector(count)] && [(NSArray *) str count] == 0)
        || [[str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] == 0;   
}
person Community    schedule 14.03.2012

на самом деле я просто исправил эту проблему, перевернув ее так

-(BOOL) isNotNullOrWhiteSpace
{
        return [self length] != 0 && [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] != 0;
}

поэтому вместо isNullOrWhiteSpace это NotNullOrWhiteSpace.

person Pinglebon    schedule 20.09.2012

Вот мой метод проверки нулевого / пустого

- (NSString *) NULLInputinitWithString: (NSString *) InputString {

if( (InputString == nil) ||(InputString ==(NSString*)[NSNull null])||([InputString isEqual:nil])||([InputString length] == 0)||([InputString isEqualToString:@""])||([InputString isEqualToString:@"(NULL)"])||([InputString isEqualToString:@"<NULL>"])||([InputString isEqualToString:@"<null>"]||([InputString isEqualToString:@"(null)"])||([InputString isEqualToString:@"NULL"]) ||([InputString isEqualToString:@"null"])))

    return @"";
else
    return InputString ;

}

person tania_S    schedule 08.12.2015

Вы думали о создании метода класса для категории, расширяющей NSString?

NSString + NSStringExtensions.h

#import <Foundation/Foundation.h>

@interface NSString(NSStringExtensions)
+(BOOL)isNilOrEmpty:(NSString*)string;
@end

NSString + NSStringExtensions.m

#import "NSString+NSStringExtensions.h"

@implementation NSString(NSStringExtensions)

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

@end

Затем вы используете это так:

#import "NSString+NSStringExtensions.h"
...
NSLog([NSString isNilOrEmpty:@""] ? @"1":@"0");
person HairOfTheDog    schedule 08.01.2014
comment
сделайте это одной строкой: return string.length == 0;. и не называйте NSLog таким образом - person Bryan Chen; 08.01.2014
comment
@BryanChen Я не пишу много Ocjective-C. Вы можете объяснить, почему нельзя так называть NSLog? - person HairOfTheDog; 06.11.2014
comment
это должно быть NSLog(@"%@", [NSString isNilOrEmpty:@""] ? @"1":@"0") или NSLog(@"%d", [NSString isNilOrEmpty:@""] ? 1 : 0) - person Bryan Chen; 06.11.2014