Строка isNullOrEmpty как категория - PullRequest
2 голосов
/ 14 марта 2012

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

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

@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.

Ответы [ 9 ]

5 голосов
/ 15 марта 2012
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, но вас вводит в заблуждение представление *1040*, которое NSLog выбирает при печати nil:

NSLog(@"%@", nil);

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

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

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

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

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

1 голос
/ 15 марта 2012

Другим подходом может быть определение простого макроса.

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

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

- Обновление:

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

#define NSStringIsNullOrEmpty(str) ({ NSString *_str=(str); ((tmp==nil) || [tmp isEqualToString:@""]);})
0 голосов
/ 08 декабря 2015

Вот мой метод проверки null / empty

- (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 ;

}

0 голосов
/ 08 января 2014

Задумывались ли вы о создании метода класса для категории, которая расширяет 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");
0 голосов
/ 20 сентября 2012

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

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

, поэтому вместо isNullOrWhiteSpace это isNotNullOrWhiteSpace.

0 голосов
/ 15 марта 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;   
}
0 голосов
/ 15 марта 2012

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

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

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

0 голосов
/ 15 марта 2012

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

0 голосов
/ 15 марта 2012

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

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

...