通常,您需要编写如下代码:
if someOptional != nil {
// do something with the unwrapped someOptional e.g.
someFunction(someOptional!)
}
这似乎有点冗长,而且我听说使用!
force unwrap操作符是不安全的,最好避免.有没有更好的方法来处理这个问题?
通常,您需要编写如下代码:
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)
}
else
第must部分退出保护值的范围,例如return
或fatalError
,以保证保护值在该范围的其余部分有效.
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) }
但现在idx
是Int??
型,一个双可选.相反,您可以使用flatMap
,它将结果"展平"为一个选项:
let idx = fst.flatMap { find($0, 2) }
// idx will be of type Int?
// and not Int?? unlike if `map` was used