检查可选数组是否为空


74

在Objective-C中,当我有一个数组时

NSArray *array;

我想检查它是否不为空,我总是这样做:

if (array.count > 0) {
    NSLog(@"There are objects!");
} else {
    NSLog(@"There are no objects...");
}

这样一来,无需检查是否会array == nil因为这种情况导致代码陷入该else情况,以及非但nil空数组都可以。

但是,在Swift中,我偶然发现了一个可选数组:

var array: [Int]?

而且我不知道要使用哪种条件。我有一些选择,例如:

选项A:nil在相同条件下检查非用例和空用例:

if array != nil && array!.count > 0 {
    println("There are objects")
} else {
    println("No objects")
}

选项B:使用解除绑定数组let

if let unbindArray = array {
    if (unbindArray.count > 0) {
        println("There are objects!")
    } else {
        println("There are no objects...")
    }
} else {
    println("There are no objects...")
}

选项C:使用Swift提供的合并运算符:

if (array?.count ?? 0) > 0 {
    println("There are objects")
} else {
    println("No objects")
}

我不太喜欢选项B,因为我会在两种情况下重复执行代码。但是我不确定选项AC是否正确,还是应该使用其他任何方式来做到这一点。

我知道可以根据情况避免使用可选数组,但是在某些情况下,可能有必要询问它是否为空。所以我想知道最简单的方法是什么。


编辑:

正如@vacawama指出的,这种简单的检查方法有效:

if array?.count > 0 {
    println("There are objects")
} else {
    println("No objects")
}

但是,我尝试的情况是仅当它为nil空或为空时才想做一些特别的事情,然后继续执行该操作,而不管该数组是否包含元素。所以我尝试了:

if array?.count == 0 {
    println("There are no objects")
}

// Do something regardless whether the array has elements or not.

并且

if array?.isEmpty == true {
    println("There are no objects")
}

// Do something regardless whether the array has elements or not.

但是,当array为时nil,它不会掉入if体内。这是因为在这种情况下,array?.count == niland array?.isEmpty == nil,因此表达式array?.count == 0array?.isEmpty == true都计算为false

因此,我试图找出是否还有一种方法可以仅通过一个条件来实现这一目标。


您是否有理由将数组设置为可选?对于表视图和其他东西,我使用了非可选的,因为(如您所说)nil与没有对象相同,因此通过删除nil可以降低复杂性而又不会失去任何功能。
Fogmeister 2014年

我认为该选项A最易读。那只是您应该关心的事情。
苏珊(Sulthan)2014年

Answers:


141

更新了Swift 3及更高版本的答案:

Swift 3删除了与>和比较可选选项的功能<,因此先前答案的某些部分不再有效。

仍然可以将可选参数与进行比较==,因此检查可选数组是否包含值的最直接方法是:

if array?.isEmpty == false {
    print("There are objects!")
}

其他可以完成的方式:

if array?.count ?? 0 > 0 {
    print("There are objects!")
}

if !(array?.isEmpty ?? true) {
    print("There are objects!")
}

if array != nil && !array!.isEmpty {
    print("There are objects!")
}

if array != nil && array!.count > 0 {
    print("There are objects!")
}

if !(array ?? []).isEmpty {
    print("There are objects!")
}

if (array ?? []).count > 0 {
    print("There are objects!")
}

if let array = array, array.count > 0 {
    print("There are objects!")
}

if let array = array, !array.isEmpty {
    print("There are objects!")
}

如果要在数组nil为空或为空时执行某些操作,则至少有6个选择:

选项A:

if !(array?.isEmpty == false) {
    print("There are no objects")
}

选项B:

if array == nil || array!.count == 0 {
    print("There are no objects")
}

选项C:

if array == nil || array!.isEmpty {
    print("There are no objects")
}

选项D:

if (array ?? []).isEmpty {
    print("There are no objects")
}

选项E:

if array?.isEmpty ?? true {
    print("There are no objects")
}

选项F:

if (array?.count ?? 0) == 0 {
    print("There are no objects")
}

选项C准确地记录了您用英语描述的方式:“我只想在nil或为空时做一些特别的事情。” 我建议您使用它,因为它很容易理解。这没有什么错,特别是因为如果变量为,它将“短路”并跳过对空的检查nil



Swift 2.x的先前答案:

您可以简单地执行以下操作:

if array?.count > 0 {
    print("There are objects")
} else {
    print("No objects")
}

正如@Martin在注释中指出的那样,它使用func ><T : _Comparable>(lhs: T?, rhs: T?) -> Bool表示编译器将其包装0为,Int?以便可以与左侧进行比较,这是Int?由于可选的链接调用所致。

以类似的方式,您可以执行以下操作:

if array?.isEmpty == false {
    print("There are objects")
} else {
    print("No objects")
}

注意:您必须与false此处明确比较才能正常工作。


如果要在数组nil为空或为空时执行某些操作,则至少有7个选择:

选项A:

if !(array?.count > 0) {
    print("There are no objects")
}

选项B:

if !(array?.isEmpty == false) {
    print("There are no objects")
}

选项C:

if array == nil || array!.count == 0 {
    print("There are no objects")
}

选项D:

if array == nil || array!.isEmpty {
    print("There are no objects")
}

选项E:

if (array ?? []).isEmpty {
    print("There are no objects")
}

选项F:

if array?.isEmpty ?? true {
    print("There are no objects")
}

选项G:

if (array?.count ?? 0) == 0 {
    print("There are no objects")
}

选项D准确地记录了您用英语描述的方式:“我只想在nil或为空时做一些特别的事情。” 我建议您使用它,因为它很容易理解。这没有什么错,尤其是因为如果变量为,它将“短路”并跳过对空的检查nil


2
这可行。仅出于完整性考虑:它使用func ><T : _Comparable>(lhs: T?, rhs: T?) -> Bool运算符,并且右侧由编译器0包装为Int?
马丁R

1
我只注意到有var opt : Int? = nilopt < 0计算结果为true。它在这里无关紧要,但可能是意外的,并且可能是反对比较可选整数的参数。
Martin R

nil小于Int您抛出的任何非nil值,甚至是负数。它必须在包装类型的一端或另一端,因为的任何实现<都必须是总顺序,并且optional可以包装任何可比较的类型。我认为nil比直观的东西要少,因为如果有人对一列可能为空的数字进行排序,我认为他们希望空格位于1之前。或者,nil数组变量比空值还要空。数组:)
空速2014年

谢谢@vacawama。您指出的选项有效。但是,我走得更远,尝试了另一种特殊情况:仅测试数组是否为nil或为空,无论数组是否包含元素时都进行任何操作。我将编辑我的问题,以便您查看。
eze.scaruli 2014年

2
@Rambatino,!(array?.isEmpty == false)将为trueif arrayis nil,但array?.isEmpty == true将为falseif arrayis是nil因为nil不等于true。我们想将anil array视为空。
vacawama

8

Collection协议的扩展属性

*写在Swift 3

extension Optional where Wrapped: Collection {
    var isNilOrEmpty: Bool {
        switch self {
            case .some(let collection):
                return collection.isEmpty
            case .none:
                return true
        }
    }
}

使用示例:

if array.isNilOrEmpty {
    print("The array is nil or empty")
}

 

其他选择

除了上面的扩展名,我发现以下选项最清晰,没有强制展开可选的选项。我将其理解为解包可选数组,如果没有,则将其替换为相同类型的空数组。然后,获取该结果的(非可选)结果,并isEmpty执行条件代码。

推荐的

if (array ?? []).isEmpty {
    print("The array is nil or empty")
}

尽管以下内容很清楚,但我建议养成一种习惯,即尽可能避免强制展开可选内容。虽然你是保证array绝不会nilarray!.isEmpty这个特定的情况下被执行,这将在以后很容易编辑和无意中引入崩溃。当您习惯于强行打开可选组件时,您会增加某些人将来进行更改而编译但在运行时崩溃的可能性。

不建议!

if array == nil || array!.isEmpty {
    print("The array is nil or empty")
}

我发现包含array?(可选链接)令人困惑的选项,例如:

令人困惑?

if !(array?.isEmpty == false) {
    print("The array is nil or empty")
}

if array?.isEmpty ?? true {
    print("There are no objects")
}

5

选项D:如果该数组不需要是可选的,因为您只在乎它是否为空,则将其初始化为一个空数组而不是可选的:

var array = [Int]()

现在它将一直存在,您只需检查即可isEmpty


我同意这一点,但问题是我们不知道OP到底想要什么。根据所使用的API,数组可能具有内容或为nil。或为nil,为空或包含值。并且每种情况都有不同的解决方案。
阿比森2014年

同意,我只是介绍一个我个人认为有用的选项。
jrturton 2014年

1
哈哈,是啊。在您读完答案之前,我只是评论了这件事。好主意... :-)
Fogmeister 2014年

表视图正是我正在考虑的情况!
jrturton 2014年

5

Swift 3-4兼容:

extension Optional where Wrapped: Collection {
        var nilIfEmpty: Optional {
            switch self {
            case .some(let collection):
                return collection.isEmpty ? nil : collection
            default:
                return nil
            }
        }

        var isNilOrEmpty: Bool {
            switch self {
            case .some(let collection):
                return collection.isEmpty
            case .none:
                return true
        }
}

用法:

guard let array = myObject?.array.nilIfEmpty else { return }

要么

if myObject.array.isNilOrEmpty {
    // Do stuff here
}

3

有条件的展开:

if let anArray = array {
    if !anArray.isEmpty {
        //do something
    }
}

编辑:自Swift 1.2起可能:

if let myArray = array where !myArray.isEmpty {
    // do something with non empty 'myArray'
}

编辑:自Swift 2.0起可能:

guard let myArray = array where !myArray.isEmpty else {
    return
}
// do something with non empty 'myArray'

他仍然必须检查它是否为空。这只是检查可选项是否包含数组。
阿比森2014年

是的,那么您可以做if array? != nil && !(array!.isEmpty) {}
borchero 2014年

您可以简单地对其进行解包,因为如果数组为nil并且无法解包,则该行不会执行
borchero 2014年

1
你不觉得有写array?,并array!在同一行是一个代码味道?这就是有条件展开的目的。
阿比森2014年

但是请注意,您必须使用逻辑&运算符->必须使用&&而不是&。否则,当数组为nil时,您可能会收到错误消息
borchero 2014年

1

优雅的内置解决方案是Optional的map方法。这种方法通常被遗忘,但是它确实可以满足您的需要。它使您可以安全地向包裹在Optional中的东西发送消息。在这种情况下,我们以一种三向切换结束:我们可以isEmpty对Optional数组说,并获得true,false或nil(如果数组本身为nil)。

var array : [Int]?
array.map {$0.isEmpty} // nil (because `array` is nil)
array = []
array.map {$0.isEmpty} // true (wrapped in an Optional)
array?.append(1)
array.map {$0.isEmpty} // false (wrapped in an Optional)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.