对于使用Objective-C开发iOS的程序员来说,对象能否为nil在编写程序的过程中程序员不太关心,直接使用即可以,在少量需要判断的地方在判断,当转为Swift开发时,首先头疼的问题就是可选类型,究竟何时使用?,何时使用!总是拿不太准,下面就详细的讲解一下
可选类型伴随着Swift诞生,在原有的Objective-C语言中不存在,究其起因,是由于Swift是类型安全的语言,而OC则是弱类型语言,OC中 str字符串既可以是nil,也可以是字符串,而Swift中,这两种状态是不能同时存在的。
OC和Swift对于nil的解释也是不太一样的
1.Objective-C中的nil:表示缺少一个合法的对象,是指向不存在对象的指针,对结构体、枚举等类型不起作用(会返回NSNotFound)
2.Swift中的nil:表示任意类型的值缺失,是一个确定的值,要么是该类型的一个值要么什么都没有(即为nil)
在Swift中Optional(可选类型)是一个含有两种情况的枚举,None 和 Some(T),用来表示可能有或者可能没有值。任何类型都可以明确公告为(或者者隐式转换)可选类型。当公告一个可选类型的时候,要确保用括号给 ? 操作符一个合适的范围。
var optionalStr: String? = "swift语言可选类型"//公告可选类型字符串,并赋初值var opStu:Student? //公告可选opStu对象,赋初值nil
注意:在类型和 ?之间没有空格
当你确定自己设置的可选类型肯定有值时,可以使用操作符(!)进行强制解析,拿到数据,叹号表示"我知道肯定有值,请使用它",但是当你判断错误,可选值为nil时使用(!)进行强制解析,会有运行错误。
var myStr:String? = nilmyStr="强制解析,肯定有值"if myStr != nil { print(myStr!)//使用!进行强制解析}else{ print("字符串为nil")}
运行结果
强制解析,肯定有值
在最初的公告时使用?修饰,当你希望它自动解析是可以用!代替?来修饰,这样在变量使用时就不需要加!来强制拆包,它会自动解析。
var myStr:String! //使用!修饰myStr="自动解析"if myStr != nil { print(myStr)}else{ print("字符串为nil")}
运行结果
自动解析
A.使用可选绑定,摆脱了频繁的判断能否为nil在赋值,但是使用可选绑定(optional binding)来判断可选类型能否包含值,假如包含就把值赋给一个临时常量或者者变量。可选绑定可以用在if和while语句中来对可选类型的值进行判断并把值赋给一个常量或者者变量。
格式:
if let tempStr = someOptional{ tempStr//假如someOptiona有值的话,就会赋值给tempStr,而后使用}
var myStr:String?myStr="可选绑定"if let tempStr = myStr { print(tempStr)}else{ print("字符串为nil")}
运行结果
可选绑定
B.在可选类型判断中还有guard let的用法,guard名为守卫的意思。guard let和if let恰好相反,guard let守护肯定有值。假如没有,直接返回
let name: String? = "张三"let age: Int? = 10guard let nameNew = name, let ageNew = ageelse { print("姓名 或者 年龄 为nil") return}print("姓名 或者 年龄 为\(name),\(age)")//运行到这里是肯定有值的
在写Swift代码时总是拿不准究竟使用哪个,有时会根据编辑器的提醒去Fix,但是这样不能很好的处理问题。
1.as!使用场合
向下转型(Downcasting)时使用。因为是强制类型转换,假如转换失败会报 runtime 运行错误。就是说强制从父类转换成子类
class Animal {}class Cat: Animal {}let animal :Animal = Cat()let cat = animal as! Cat
2.as?使用场合
as? 和 as! 操作符的转换规则完全一样。但 as? 假如转换不成功的时候便会返回一个 nil 对象。成功的话返回可选类型值(optional),需要我们拆包使用。因为 as? 在转换失败的时候也不会出现错误,所以对于假如能确保100%会成功的转换则可使用 as!,否则使用 as?
let animal:Animal = Cat()if let cat = animal as? Cat{ print("cat is not nil")} else { print("cat is nil")}
在方法中返回值如Int?、String?、(Int, String)?、[Int]?、[Int: String]?等
func returnOptionValue(value: Bool) -> String? { // 返回类型为可选String类型 if value { return "返回类型是可选类型值" // 假如为真,返回Int类型的值1 } else { return nil //返回nil }}let optionValue = returnOptionValue(value: true) // 要用可选绑定判断再使用,由于returnOptionValue为String?可选类型if let value = optionValue { print(value)} else { print("none value")}
运行结果
返回类型是可选类型值
返回类型为闭包可选
func returnOptionalFunc(value: Bool) -> (() -> (Void))? { // 返回类型为可选类型的闭包 if value { return { () in print("返回类型是可选类型闭包") } } else { return nil }}let possibleFunc = returnOptionalFunc(value: true) // 要用可选绑定判断再使用,由于possibleFunc 为可选类型的闭包,类型为() -> (Void)if let aFunc = possibleFunc { print(aFunc()) // 注意添加()调用闭包,由于没有参数则是空括号} else { print("none func")}
运行结果
返回类型是可选类型闭包
可选类型在类中的使用
class PossibleClass { var someValue: Int var possibleValue: String? // 可选存储属性,默认值为nil init(someValue: Int) { // 构造方法中可以不对possibleValue属性初始化 self.someValue = someValue }}let someClass = PossibleClass(someValue: 4)
可选类型在结构体中的运用
struct PossibleStruct { var someValue: Int var possibleValue: String? // 可选存储属性,默认值为nil // 结构体中可以自己设置一个init构造器对属性初始化,也可以不自己设置}let someStruct = PossibleStruct(someValue: 4, possibleValue: nil)
class PossibleStructInit { let someValue: String init?(someValue: String) { // 可失败构造器 if someValue.isEmpty { return nil } // 假如实例化为空串,则返回nil(即实例化失败) self.someValue = someValue }}let oneStruct = PossibleStructInit(someValue: "构造器中使用") // abc不是空串,oneStruct为PossibleStructInit?可选类型if let one = oneStruct { // 使用if let可选绑定判断 print(one.someValue)} else { print("none value")}//输入结果为:构造器中使用let twoStruct = PossibleStructInit(someValue: "") // 传参为空串if let two = twoStruct { print(two.someValue)} else { print("none value")}//输入结果为:none value
1.try?会将错误转换为可选值,当调用try?+函数或者方法语句时候,假如函数或者方法抛出错误,程序不会发崩溃,而返回一个nil,假如没有抛出错误则返回可选值。
2.使用try!可以打破错误传播链条。错误抛出后传播给它的调用者,这样就形成了一个传播链条,但有的时候的确不想让错误传播下去,可以使用try!语句
let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")// 上述语句中在执行loadImage方法时假如执行失败,使用try!来禁用错误传递,会有运行错误导致App崩溃
func someThrowingFunction() throws -> Int { // ...}let x = try? someThrowingFunction() // x可能正常返回一个Int类型的值也有可能抛出一个错误异常,使用时对x用if let可选绑定判断