在Objective-C中检查空字符串的正确方式是什么?

193

我在我的 iPhone 应用程序中使用了这个。

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

但是它抛出了一些异常,控制台显示标题为“(null)”。

所以我现在使用这个:

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

什么是差异,以及确定字符串是否为null的最佳方法是什么?


解决方案:http://jayprakashdubey.blogspot.in/2014/09/better-way-to-check-empty-string.html - Jayprakash Dubey
20个回答

408

正如其他人指出的那样,在Cocoa/Objective C中有许多种“null”。但还要注意的一件事是,[title isKindOfClass:[NSNull class]] 是毫无意义的复杂,因为[NSNull null] 被记录为单例,所以你可以检查指针相等性。请参阅Topics for Cocoa: Using Null

所以一个好的测试可能是:

if (title == (id)[NSNull null] || title.length == 0 ) title = @"Something";
注意,即使标题为nil,title.length将返回0/nil/false,即在此情况下为0,因此您无需特别处理它。这是Objective C新手很难习惯的事情,尤其是来自其他语言的消息/方法调用到nil会导致崩溃。

1
标题应该是什么类型?例如,如果它是NSString,则会收到以下警告:comparison of distinct Objective-C types 'struct NSNull *' and 'struct NSString *' lacks a cast是否有任何方法可以消除这个问题(我不知道自从提出这个问题以来是否有所改变)? - thebossman
1
我没编译就发布代码,这是我的错;)。标题可能是NSString类型,但无论标题的类型如何,只需将null强制转换为通用id类型:(id)[NSNull null]。 - Peter N Lewis
1
@JLT nil和[NSNull null]不是同一回事。[NSNull null]是一个单例对象,可以用作nil的替代品,当不能使用nil时(例如在NSArray或NSDictionary值中)。因此,使用情况可能是您有一个可选字符串的NSArray,其中一些可能为null,并且您在数组中使用[NSNull null]来表示null情况。实际上,很少需要测试,只有在您(或您使用的库!)积极使用[NSNull null]作为占位符时才需要。 - Peter N Lewis
主要区别在于nil是一个指向空值的指针(实际上是“空指针”),它由C语言中的NULL表示,其内存地址为0x0。而另一方面,[NSNull null]是一个被约定为null值表示的对象(它与0x0内存地址不同,但作为单例,在运行时只会占用一个固定的内存地址)。由于像NSArray *NSDictionary *等集合不能接受空指针,因此它们可以毫无问题地接受[NSNull null],因为它是一个已实例化的对象。 - Alejandro Iván
1
从Flutter转来,想知道为什么Dart中的Map项目的值(即在Dart中为null)与Objective C中的nilNULL不相对应。原因是它实际上是NUNull null,而不是NULL null。谢谢@PeterNLewis! - Aleksandar
显示剩余3条评论

25

这很简单

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

请记住,在 Objective-C 中,如果对象为 null,它将返回值为 0。

这将使您获得空字符串和长度为 0 的字符串。


52
如果对象是 NSNull,这样做就行不通,仍然需要明确地首先检查它。 - Jeremy Mack
6
你可以为 NSNull 创建一个分类,使其在收到 length 消息时返回 0 :) - Mihai Timar
1
是的,如果对象是NSNull,这将会崩溃。 - Mike Gledhill
如果对象等于NSNull,这将导致崩溃。 - joan
1
除了NSNull未识别选择器问题外,这也无法区分NSString指针是否为nil,或者实际上存在但本质上是空字符串的NSString。(例如作为文字“object = @"";”或“object = nil;”) - KellyHuberty
如果字符串只是空的,但不是nil怎么办? - Kevin

6
我发现为了做到真正的正确,你最终需要做类似于以下的事情:
if ( ( ![myString isEqual:[NSNull null]] ) && ( [myString length] != 0 ) ) {
}

否则你会遇到奇怪的情况,控制流仍然会绕过你的检查。我还没有遇到一个通过isEqual和长度检查的情况。

6

很烦人的是,我没有足够的“积分”来添加第二个超链接(即使是指向本网站上的内容) 另请参阅:- http://stackoverflow.com/questions/598396/proper-checking-of-nil-sqlite-text-column - TimM
...让我来帮你。虽然你应该能够从声望为0的时候开始编辑自己的帖子。 - Rog
谢谢 - 非常感谢。当我写我的初始帖子时,它说新用户只能添加1个超链接(这似乎有点严厉 - 特别是对于此站点中的交叉链接)。 - TimM

5

为什么会有那么多"只适合我自己的答案"?我们都在使用同一种语言编程,而规则是:

  1. 确保引用不为空
  2. 检查并确保字符串长度不为0

这样做对于所有人都是有效的。如果某个解决方案只是"只适合你自己",那只是因为你的应用程序流程不允许出现引用为空或字符串长度为0的情况。正确的方法是处理所有情况下所需的方法。


4
如果参考对象是 *nil*(注意不是 "null"),则发送消息(例如 length)将产生 0(或方法返回类型的适当 0 值)。这就是语言的规定。在这种情况下,无需单独检查 nil - jscs
我之所以说null,只是因为C++的习惯,如果你的代码在调用nil对象的方法,那么你的代码很可能是有问题的。你会发现,在任何语言中,调用NULL/NIL(同一概念)的方法通常都不是一个好主意。仅仅因为obj-c允许你这样做,并不意味着你应该随意传递nil对象并尝试在不关心它们的情况下使用它们。 - nenchev
1
将长度发送到nil确实会产生0 - 但是将长度发送到NSNull会产生异常。 - chris stamper
@nenchev 没有人说仅传递空对象,但是在检查空值后调用方法并使用其返回值,我认为比使用语言特性更糟糕,因为应该按照其设计意图使用语言特性,并在之后检查方法的返回值的有效性。 - Kevin
@Kevin 我不确定它为什么更糟,仅仅因为它是一种语言特性并不意味着它很棒。不检查它是否为空可能会打开一个代码路径,导致更难追踪的运行时错误。通常最好验证您的输入是否符合预期,并根据情况做出反应。我个人不喜欢在尝试向空对象发送消息时不会得到运行时异常的“特性”,因为这经常使得错过一些运行时错误变得更容易。 - nenchev

4

如果你想测试所有的nil/空对象(例如空字符串或空数组/集合),你可以使用以下方法:

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],这可能是有意义的。 - Peter N Lewis

4
有两种情况:
一个对象有可能是[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 的字符串。如果你将其视为nil字符串处理,则测试(object.length == 0)。如果object == nil,则 object.length 将返回 0,因此该测试涵盖了没有对象和长度为 0 的字符串。如果你将长度为 0 的字符串与 nil 字符串视为不同的字符串,只需检查object == nil
最后,如果你想将一个字符串添加到数组或字典中,并且该字符串可能为空,你可以选择不添加它,用@""替换它,或用[NSNull null]替换它。用@""替换它意味着你失去了区分“没有字符串”和“长度为 0 的字符串”的能力。用[NSNull null]替换它意味着你必须编写访问数组或字典时检查[NSNull null]对象的代码。

非常长,但这很好。NSNull应该仅出现在单例中!整个问题毫无意义,告诉我编码者没有做正确的事情,并且在将来的许多情况下,也没有阅读手册/良好的代码实践。 - Stephen J

3

你只需要检查是否为nil

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

或者

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

2

MACRO解决方案(2020)

以下是我用于安全字符串的宏,而不是在UILabel上获取"(null)"字符串的示例:

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

假设你有一个成员类(member class)和名字属性(name property),并且名字是nil(空):

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

使用宏:

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

干净整洁

扩展解决方案 (2020)

如果您在项目中更喜欢检查 nil、Null 和空字符串,可以使用以下扩展代码:

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

示例用法

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接