通常,您需要编写如下代码:
if someOptional != nil { // do something with the unwrapped someOptional e.g. someFunction(someOptional!) }
这似乎有点冗长,而且我还听说使用!强制解包运算符可能是不安全的,最好避免使用。有没有更好的方法来解决这个问题?
!
几乎总是没有必要检查可选项是否没有nil。几乎唯一需要这样做的时间是,如果它的nil-ness是 唯一 要了解的内容–您不在乎值的含义,而不必在意nil。
nil
在大多数其他情况下,还有一些Swift速记可以更安全,简洁地if为您完成任务。
if
如果不是,则使用该值nil
代替:
let s = "1" let i = Int(s) if i != nil { print(i! + 1) }
您可以使用if let:
if let
if let i = Int(s) { print(i + 1) }
您也可以使用var:
var
if var i = Int(s) { print(++i) // prints 2 }
但请注意,这i将是 本地 副本-对其所做的任何更改i都不会影响原始可选内容中的值。
i
您可以在单个内解开多个可选选项if let,以后的选项可以取决于以前的选项:
if let url = NSURL(string: urlString), data = NSData(contentsOfURL: url), image = UIImage(data: data) { let view = UIImageView(image: image) // etc. }
您还where可以在未包装的值中添加子句:
where
if let url = NSURL(string: urlString) where url.pathExtension == "png", let data = NSData(contentsOfURL: url), image = UIImage(data: data) { etc. }
替换nil为默认值
let j: Int if i != nil { j = i } else { j = 0 }
要么:
let j = i != nil ? i! : 0
您可以使用nil-coalescing运算子??:
??
// j will be the unwrapped value of i, // or 0 if i is nil let j = i ?? 0
将可选与非可选等同
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总是等于其他nils,并且小于任何非nil值。
小心!这里可能有陷阱:
let a: Any = "hello" let b: Any = "goodbye" if (a as? Double) == (b as? Double) { print("these will be equal because both nil...") }
调用可选方法(或读取属性)
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情况。稍后,您可以在此答案中使用其他技术之一来处理js的可选性,但是您通常可以将实际展开可选对象的时间推迟到很久以后,有时甚至根本不进行。
j
fatalError
顾名思义,您可以将它们链接起来,因此可以编写:
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}
分配给可选属性
if splitViewController != nil { splitViewController!.delegate = self }
您可以 通过 可选链进行分配:
splitViewController?.delegate = self
只有在splitViewController非nil分配情况下才会发生。
splitViewController
使用值,如果不是nil或,则使用值(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") } }
但是最好将错误处理代码保持在检查的顶部。这也可能导致令人不快的嵌套(“厄运金字塔”)。
相反,您可以使用guard,它类似于if not let:
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) }
该else零件 必须 退出保护值的范围,例如a return或fatalError,以确保该保护值对其余范围有效。
else
return
guard不限于功能范围。例如以下内容:
var a = ["0","1","foo","2"] while !a.isEmpty { guard let i = Int(a.removeLast()) else { continue } print(i+1, appendNewline: false) }
版画321。
321
循环处理序列中的非零项目(Swift 2.0中的新增功能)
如果有一系列可选参数,则可以用于for case let _?遍历所有非可选元素:
for case let _?
let a = ["0","1","foo","2"] for case let i? in a.map({ Int($0)}) { print(i+1, appendNewline: false) }
版画321。这是将模式匹配语法用于可选内容,即变量名后跟?。
?
您还可以在switch语句中使用此模式匹配:
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
循环直到函数返回nil
很像if let,您还可以编写while let和循环直到nil:
while let
while let line = readLine() { print(line) }
您还可以编写while var(要if var应用类似的警告)。
while var
if var
where 子句在这里也起作用(并终止循环,而不是跳过):
while let line = readLine() where !line.isEmpty { print(line) }
将可选参数传递给采用非可选参数并返回结果的函数
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...") }
您可以使用可选的map运算符:
map
let j = i.map { abs($0) }
这是非常相似的可选链接,但对于当你需要的非可选值传递 到 函数作为参数。与可选链接一样,结果将是可选的。
无论如何,如果您想要一个可选的,这是很好的。例如,reduce1like reduce,但是使用第一个值作为种子,如果数组为空,则返回一个可选值。您可以这样写(使用guard前面的关键字):
reduce1
reduce
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
但是您可以选择map该.first属性,然后返回该属性:
.first
extension Array { func reduce1(combine: (T,T)->T)->T? { return self.first.map { dropFirst(self).reduce($0, combine: combine) } } }
传递一个可选参数到一个接受可选参数并返回结果的函数中,避免烦人的双可选参数
有时,您想要类似于的东西map,但是您要调用的函数 本身 返回一个可选的。例如:
// 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) }
但现在idx的类型为Int??,是双精度可选。相反,您可以使用flatMap,将结果“展平”为单个可选内容:
idx
Int??
flatMap
let idx = fst.flatMap { find($0, 2) } // idx will be of type Int? // and not Int?? unlike if `map` was used