通常,您需要编写如下代码:

if someOptional != nil {
    // do something with the unwrapped someOptional e.g.       
    someFunction(someOptional!)
}

这似乎有点冗长,而且我听说使用! force unwrap操作符是不安全的,最好避免.有没有更好的方法来处理这个问题?

推荐答案

几乎总是不需要判断可选项是否不是nil.几乎你唯一需要做的就是,如果它的nil度是你想知道的only度——你不在乎它的值是多少,只是它不是nil.

在大多数其他情况下,有一点快速的速记,可以更安全和简洁地完成任务内的if为你.

Using the value if it isn’t 100

而不是:

let s = "1"
let i = Int(s)

if i != nil {
    print(i! + 1)
}

你可以使用if let:

if let i = Int(s) {
    print(i + 1)
}

您还可以使用var:

if var i = Int(s) {
    print(++i)  // prints 2
}

但请注意,i将是local副本-对i的任何更改都不会影响原始可选文件中的值.

您可以在一个if let个选项中展开多个选项,后面的选项可以依赖于前面的选项:

if let url = NSURL(string: urlString),
       data = NSData(contentsOfURL: url),
       image = UIImage(data: data)
{
    let view = UIImageView(image: image)
    // etc.
}

还可以向展开的值添加where个子句:

if let url = NSURL(string: urlString) where url.pathExtension == "png",
   let data = NSData(contentsOfURL: url), image = UIImage(data: data)
{ etc. }

Replacing 100 with a default

而不是:

let j: Int
if i != nil {
    j = i
}
else {
    j = 0
}

或者:

let j = i != nil ? i! : 0

可以使用nil凝聚运算符??:

// j will be the unwrapped value of i,
// or 0 if i is nil
let j = i ?? 0

Equating an optional with a non-optional

而不是:

if i != nil && i! == 2 {
    print("i is two and not nil")
}

您可以判断可选值是否等于非可选值:

if i == 2 {
    print("i is two and not nil")
}

这也适用于比较:

if i < 5 { }

nil始终等于其他nil,并且小于任何非nil值.

小心!这里可能有trap :

let a: Any = "hello"
let b: Any = "goodbye"
if (a as? Double) == (b as? Double) {
    print("these will be equal because both nil...")
}

Calling a method (or reading a property) on an optional

而不是:

let j: Int
if i != nil {
    j = i.successor()
}
else {
   // no reasonable action to take at this point
   fatalError("no idea what to do now...")
}

您可以使用可选链接,?.:

let j = i?.successor()

注意,j现在也将是可选的,以说明fatalError场景.稍后,你可以使用这个答案中的其他技术之一来处理j的可选性,但你通常可以推迟到很久以后,或者有时根本不需要.

顾名思义,你可以链接它们,这样你就可以写:

let j = s.toInt()?.successor()?.successor()

可选链接也适用于下标:

let dictOfArrays: ["nine": [0,1,2,3,4,5,6,7]]
let sevenOfNine = dictOfArrays["nine"]?[7]  // returns {Some 7}

和功能:

let dictOfFuncs: [String:(Int,Int)->Int] = [
      "add":(+),
      "subtract":(-)
]

dictOfFuncs["add"]?(1,1)  // returns {Some 2}

Assigning to a property on an optional

而不是:

if splitViewController != nil {
    splitViewController!.delegate = self 
}

您可以指定through个可选链:

splitViewController?.delegate = self

只有当splitViewController为非nil时,任务才会发生.

Using the value if it isn’t 100, or bailing (new in Swift 2.0)

有时在一个函数中,你需要编写一小段代码来判断一个可选项,如果它是nil,那么尽早退出该函数,否则继续.

你可以这样写:

func f(s: String) {
    let i = Int(s)
    if i == nil { fatalError("Input must be a number") }
    print(i! + 1)
}

或者避免原力展开,如下所示:

func f(s: String) {
    if let i = Int(s) {
        print(i! + 1)
    }
    else { 
        fatalErrr("Input must be a number")
    }
}

但最好是在判断时将错误处理代码保持在顶部.这也会导致令人不快的筑巢("末日 pyramid ").

相反,你可以使用guard,就像if not let:

func f(s: String) {
    guard let i = Int(s)
        else { fatalError("Input must be a number") }

    // i will be an non-optional Int
    print(i+1)
}

elsemust部分退出保护值的范围,例如returnfatalError,以保证保护值在该范围的其余部分有效.

guard不限于功能范围.例如:

var a = ["0","1","foo","2"]
while !a.isEmpty  {
    guard let i = Int(a.removeLast())
        else { continue }

    print(i+1, appendNewline: false)
}

打印321张.

Looping over non-nil items in a sequence (new in Swift 2.0)

如果有一系列可选元素,可以使用for case let _?来迭代所有非可选元素:

let a = ["0","1","foo","2"]
for case let i? in a.map({ Int($0)}) {
    print(i+1, appendNewline: false)
}

打印321张. This is using the pattern-matching syntax for an optional, which is a variable name followed by ?.

您还可以在switch条语句中使用这种模式匹配:

func add(i: Int?, _ j: Int?) -> Int? {
    switch (i,j) {
    case (nil,nil), (_?,nil), (nil,_?):
        return nil
    case let (x?,y?):
        return x + y
    }
}

add(1,2)    // 3
add(nil, 1) // nil

Looping until a function returns 100

很像if let,你也可以写while let,循环到nil:

while let line = readLine() {
    print(line)
}

你也可以写while var条类似的警告.

where个子句在这里也起作用(并终止循环,而不是跳过):

while let line = readLine() 
where !line.isEmpty {
    print(line)
}

Passing an optional into a function that takes a non-optional and returns a result

而不是:

let j: Int
if i != nil {
    j = abs(i!)
}
else {
   // no reasonable action to take at this point
   fatalError("no idea what to do now...")
}

you can use optional’s map operat或者:

let j = i.map { abs($0) }

这与可选链接非常相似,但是当需要将非可选值into作为参数传递给函数时.与可选链接一样,结果也是可选的.

不管怎样,当你想要一个可选的时候,这很好.例如,reduce1类似于reduce,但使用第一个值作为种子,如果数组为空,则返回可选值.您可以这样写(使用前面的guard关键字):

extension Array {
    func reduce1(combine: (T,T)->T)->T? {

        guard let head = self.first
            else { return nil }

        return dropFirst(self).reduce(head, combine: combine)
    }
}

[1,2,3].reduce1(+) // returns 6

但是你可以把.first的房产换成map英镑,然后还回:

extension Array {
    func reduce1(combine: (T,T)->T)->T? {
        return self.first.map {
            dropFirst(self).reduce($0, combine: combine)
        }
    }
}

Passing an optional into a function that takes an optional and returns a result, avoiding annoying double-optionals

有时,您想要类似于map的值,但您想要调用itself的函数返回可选值.例如:

// an array of arrays
let arr = [[1,2,3],[4,5,6]]
// .first returns an optional of the first element of the array
// (optional because the array could be empty, in which case it's nil)
let fst = arr.first  // fst is now [Int]?, an optional array of ints
// now, if we want to find the index of the value 2, we could use map and find
let idx = fst.map { find($0, 2) }

但现在idxInt??型,一个双可选.相反,您可以使用flatMap,它将结果"展平"为一个选项:

let idx = fst.flatMap { find($0, 2) }
// idx will be of type Int? 
// and not Int?? unlike if `map` was used

Swift相关问答推荐

使用简单变量和函数的奇怪行为

自定义完整屏幕封面动画

解析SON数据的API调用有什么问题?

当我点击模拟器中的文本字段时,UIKit CLLocationButton崩溃

如何在向照片添加文本时定义文本对齐、文本背景的Alpha和在文本之前添加图像

如何设置两个不同的视图模型以在我的SwiftUI应用程序中使用相同的数据源?

Swift 扩展:通过方法重载增强现有类

为什么 SwiftUI 中 ForEach 的这个 Select 不起作用?

如何制作进度加载动画?

swift 是否遇到 Java 的 2gb 最大序列化大小问题?

Swift - 给定一个像 30 的 Int 如何将范围数乘以 7?

如何在 SwiftUI 中将图像传递到 2 个视图

创建 ViewModel 时 iOS 模拟器上的黑屏

用于 Swift 编码的 iOS 应用程序的 Ffmpeg

Swift 读写图片占用大量内存

Swift 自定义字体 Xcode

你如何在 UIBarItem 中使用 setTitleTextAttributes:forState?

更改日期 Select 器的文本 colored颜色

来自 ObservableObject 的绑定值

快速延迟加载属性