【问题标题】:String isNullOrEmpty as a category字符串 isNullOrEmpty 作为类别
【发布时间】:2012-03-31 08:17:38
【问题描述】:

我正在尝试创建一个检查 null/nil/空字符串的方法,并且我正在尝试让它作为一个类别工作,但没有运气。

我正在使用此代码,基于this topic 中的答案:

@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 方法时,我得到了错误。

【问题讨论】:

    标签: iphone objective-c ios null objective-c-category


    【解决方案1】:
    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 只是选择要为 nil 显示的字符串。*

    您正在做的一些事情需要它在NSObject 上的一个类别中,因此即使对象不是NSString,实际上也会调用方法

    要检查仅由空格组成的字符串,您只需在修剪空格后与空字符串@"" 进行比较:

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

    *甚至更好的是,NSLog(@"%@", [NSNull null]); 显示 <null>(尖括号而不是括号),在您遇到 NSNull 的前几次时会非常混乱。

    【讨论】:

    • 有趣。似乎让它按我想要的方式工作,我需要检查someString == nil || [someString isNullOrEmpty]
    • @Echilon:如果你把isNullOrEmpty的语义颠倒过来,变成isNotEmpty,你可以把它压缩成简单的[someString isNotEmpty],因为如果someStringnil,它会也返回 0/false/NO.
    • 这很糟糕...修剪然后检查它是否是空集?您应该遍历每个字符,如果遇到字符返回 false。
    • @pqsk:随时发布您自己的答案。不过,我不喜欢您解决方案的声音;您不能直接迭代NSString,您需要将每个字符与空白字符集进行比较。试试吧。您必须从字符串中获取每个字符,然后将其放回字符串中——浪费时间。
    • @JoshCaswell 我知道这是 2 年后的事了,但你写了我所说的。显然你不能遍历一个 NSString,这就是为什么我说“每个字符”。为什么要将它放回字符串中?就像你说的那样完全是浪费时间,但我从来没有说过这样的话。就像我说的,当有一个字符不是空白时,你会在那个时候返回 false。问题是您的解决方案在某些字符串上很好,但它不会针对任何大字符串进行扩展。
    【解决方案2】:

    另一种方法是定义一个简单的宏。

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

    简单而有效。如果您不喜欢宏,您可以随时将其转换为函数调用,而不会影响您的其余代码。

    -- 更新:

    @Bryan 提出了一个很好的观点。内联函数是一个很好的方法。这是一个更新后的宏,它只会对 str 求值一次。

    #define NSStringIsNullOrEmpty(str) ({ NSString *_str=(str); ((tmp==nil) || [tmp isEqualToString:@""]);})
    

    【讨论】:

    • 小心str 被评估两次。使用内联函数比宏好很多
    • 该函数中未定义变量 tmp,只需将 tmp 替换为 _str。 #define NSStringIsNullOrEmpty(str) ({ NSString *_str=(str); ((_str==nil) || [_str isEqualToString:@""]);})
    【解决方案3】:

    在 Objective-C 中,向 nil 发送消息将始终返回 0(或 NO、清零结构、NULL 等,取决于声明的返回类型)。当您将isNullOrEmpty 发送到nil 时,您编写的isNullOrEmpty 方法实际上不会被调用。有关详细信息,请参阅Sending a message to nil? 的已接受答案。

    也许您可以将方法更改为isNotNullOrEmpty。那么在将isNotNullOrEmpty 发送到nil 时返回值0 是有意义的。

    【讨论】:

      【解决方案4】:

      您没有调用您的方法,而是向 nil 发送消息

      【讨论】:

        【解决方案5】:

        这是预期的行为。毕竟,您正在向nil 发送消息。所以它返回 nil (或其他一些 0 值)。哪个短路为假,以便在下面显示的情况下打印“0”:

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

        您甚至可以通过在新类别方法中设置断点来确认您的消息没有被这些情况调用。

        【讨论】:

          【解决方案6】:

          正如其他人所说,调用[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;   
          }
          

          【讨论】:

            【解决方案7】:

            其实我只是把它转过来解决了这个问题

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

            所以不是 isNullOrWhiteSpace 而是 isNotNullOrWhiteSpace。

            【讨论】:

              【解决方案8】:

              这是我检查 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 ;
              

              }

              【讨论】:

                【解决方案9】:

                您是否考虑过在扩展 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");
                

                【讨论】:

                • 改为一行:return string.length == 0;。并且不要那样调用 NSLog
                • @BryanChen 我不会写很多 Ocjective-C。你能详细说明为什么不应该这样调用 NSLog 吗?
                • 应该是NSLog(@"%@", [NSString isNilOrEmpty:@""] ? @"1":@"0")NSLog(@"%d", [NSString isNilOrEmpty:@""] ? 1 : 0)
                猜你喜欢
                • 2011-01-17
                • 1970-01-01
                • 2019-03-02
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多