可选值

一、 基本概念

  1. 变量,类型,初始化
var str: String
str = "Hello World"
str.uppercaseString   
var str2: String = "Hello World2"
  1. 类型推断,强类型
var str3 = "Hello World3"
  1. 可选类型,枚举
//Optional
var errorCodeString: String?
errorCodeString = "404"
errorCodeString = nil
  • 强制解包发现为nil导致运行时崩溃,不安全!
 let theError: String = errorCodeString!
  1. if 语句
if errorCodeString != nil {
    let theError = errorCodeString!
}
  1. 可选绑定
if let theError = errorCodeString {
}
  1. 可选绑定嵌套,"Pyramid of Doom"
if let theError = errorCodeString {
    if let errorCodeInteger = Int(theError) {
        if errorCodeInteger == 404 {
        print("\(theError): \(errorCodeInteger)")
        }
    }
}
  1. 简化,都不为nil时执行。where相当于if判断语句
if let theError = errorCodeString, errorCodeInteger = Int(theError) where errorCodeInteger == 404 {
    print("\(theError): \(errorCodeInteger)")
}

4 .隐式解包的可选 -- 不安全!

var errorCodeString2: String!
errorCodeString2 = "404"
errorCodeString2 = nil
  • 如果为nil,导致运行时崩溃,不安全!
let theError2: String = errorCodeString2
  • 万能的 if, 可选绑定
if errorCodeString2 != nil {
    let theError2: String = errorCodeString2
}
if let theError2 = errorCodeString2 {
    print(theError2)
}

注意:
如果一个变量之后可能变成nil的话请不要使用隐式解包的可选类型。
如果你需要在变量的生命周期中判断是否是nil的话,请使用普通可选类型。

二、安全地使用可选值

  1. Swift 的可选类型可以⽤来表⽰可能缺失或是计算失败的值。
let cities = ["Paris": 2241, "Madrid": 3165, "Amsterdam": 827, "Berlin": 3562]
let madridPopulation: Int? = cities["Madrid"]
if madridPopulation != nil {
    print ("The population of Madrid is \(madridPopulation! * 1000)")
} else {
    print ("Unknown city: Madrid")
}
  1. 可选绑定,可以让你避免写 ! 后缀。不再需要显式地使⽤强制解包。
if let madridPopulation = cities["Madrid"] {
    print ("The population of Madrid is \(madridPopulation * 1000)")
} else {
    print ("Unknown city: Madrid")
}
  1. 空合运算符
let madridPopulationValue: Int
if madridPopulation != nil {
 madridPopulationValue = madridPopulation!
} else {
 madridPopulationValue = 1000
}
//a != nil ? a! : b
//a ?? b
let madridPopulationValue2 = madridPopulation != nil ? madridPopulation! : 1000
let madridPopulationValue3 = madridPopulation ?? 1000
// autoclosure 类型标签来避开创建显式闭包 myOptional ?? myDefaultValue -> myOptional ?? { myDefaultValue }
  1. 可选链
    可选链式调用(Optional Chaining)是一种可以在当前值可能为nil的可选值上请求和调用属性、方法及下标的方法。如果可选值有值,那么调用就会成功;如果可选值是nil,那么调用将返回nil。多个调用可以连接在一起形成一个调用链,如果其中任何一个节点为nil,整个调用链都会失败,即返回nil。
struct Order {
    let orderNumber: Int
    let person: Person?
}
struct Person {
    let name: String
    let address: Address?
}
struct Address {
    let streetName: String
    let city : String
    let state: String?
}
let order = Order(orderNumber: 1, person: nil)
// order.person!.address!.state!
if let myPerson = order.person {
    if let myAddress = myPerson.address {
        if let myState = myAddress.state {
        }
}
}
  • 使⽤问号运算符来尝试对可选类型进⾏解包。当任意⼀个组成项失败时,整条语句链将返回 nil。
if let myState = order.person?.address?.state {
    print ("This order will be shipped to \(myState)")
} else {
    print ("Unknown person, address, or state.")
}
  1. 分支上的可选值
  • switch 语句
switch madridPopulation {
case 0?: print ("Nobody in Madrid")
case (1..<1000)?: print ("Less than a million in Madrid")
case .Some(let x): print ("\(x) people in Madrid")
case .None: print("We don't know about Madrid")  
}
  1. guard 语句: 在当⼀些条件不满⾜时,可以尽早退出当前作⽤域,避免不必要的计算。可以使⽤⾮可选的 population 值,⽐嵌套 if let 语句时更简单。
func populationDescriptionForCity(city: String) -> String? {
    guard city != "madrid" else { return nil }
    if city == "madrid" {
        return nil
    } 
    guard let population = cities[city ] else { return nil }
    return "The population of Madrid is \(population * 1000)"
    if let population = cities[city ] {
        return "The population of Madrid is \(population * 1000)"
    } else {
        return nil
    } 
}
  1. 可选映射 : 若可选值存在,你可能会想操作它,否则返回 nil。
madridPopulation.map { (<#Int#>) -> U in 
}
madridPopulation.flatMap { (<#Int#>) -> U? in
}
let capitals = [
    "France": "Paris",
    "Spain": "Madrid",
    "The Netherlands": "Amsterdam",
    "Belgium": "Brussels"
]
func populationOfCapital(country: String) -> Int? {
    guard let capital = capitals[country], population = cities[capital]
        else { return nil }
    return population * 1000
}
func populationOfCapital2(country: String) -> Int? {
    return capitals[country].flatMap { capital in
        cities [capital].flatMap { population in
            return population * 1000
        }
    }
}
func populationOfCapital3(country: String) -> Int? {
    return capitals[country].flatMap { capital in
        return cities [capital]
        }.flatMap { population in
            return population * 1000
    }
}
  1. 为什么使用可选值?

强⼤的类型系统能在代码执⾏前捕获到错误,⽽且显式可选类型有助于避免由缺失值导致的意外崩溃。

//NSString *someString = ...;
//if ([ someString rangeOfString:@"swift"].location != NSNotFound) {
//    NSLog(@"Someone mentioned swift!");
//}
//
//if let someString = ... {
//if someString.rangeOfString("swift").location != NSNotFound {
//print ("Found")
//}
//}

三、map 和 flatMap 的其他用法

// CollectionType :  SequenceType
// public func map(@noescape transform: (Self.Generator.Element) throws -> T) rethrows -> [T]

// SequenceType
// public func flatMap(transform: (Self.Generator.Element) throws -> S) rethrows -> [S.Generator.Element]
// public func flatMap(@noescape transform: (Self.Generator.Element) throws -> T?) rethrows -> [T]

let numbers = [1,2,3,4]
var result = numbers.map { $0 + 2 }
// [3,4,5,6]
result = numbers.flatMap { $0 + 2 }
// [3,4,5,6]


// s.flatMap(transform) == Array(s.map(transform).flatten())
let numbersCompound = [[1,2,3],[4,5,6]];
var res = numbersCompound.map { $0.map{ $0 + 2 } }
// [[3, 4, 5], [6, 7, 8]]
var flatRes = numbersCompound.flatMap { $0.map{ $0 + 2 } }
// [3, 4, 5, 6, 7, 8]

// s.flatMap(transform) == s.map(transform).filter{ $0 != nil }.map{ $0! }
let optionalArray: [String?] = ["AA", nil, "BB", "CC"];
var optionalResult: [String] = optionalArray.flatMap{ $0 }
// ["AA", "BB", "CC"]

你可能感兴趣的:(可选值)