做者:fengsh998
原文地址:http://blog.csdn.net/fengsh998/article/details/28904115
可选类型、隐式可选类型 swift
在swift中,可选类型其根源是一个枚举型,里面有None和Some两种类型。其实所谓的nil就是Optional.None, 非nil就是Optional.Some, 而后会经过Some(T)包装(wrap)原始值,这也是为何在使用Optional的时候要拆包(从enum里取出来原始值)的缘由, 也是PlayGround会把Optional值显示为相似{Some "hello world"}的缘由,这里是enum Optional的定义: app
- enum Optional<T> : LogicValue, Reflectable {
- case None
- case Some(T)
- init()
- init(_ some: T)
-
- /// Allow use in a Boolean context.
- func getLogicValue() -> Bool
-
- /// Haskell's fmap, which was mis-named
- func map<U>(f: (T) -> U) -> U?
- func getMirror() -> Mirror
- }
语法使用“?”操做符及"!"号操做符 学习
如:“var optionalString: String? = "Hello"
optionalString == nil
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \(name)"
}”
你们把optionalName改成nil时看一下会有什么结果?按照理解,应该是? = 后的为可选值,即当咱们的的变量为nil时,这里若是有?=操做,则会使用?=后的值做为默认值,而不会为nil. 这个等有环境时,验证一下。 测试
经验证: ui
分别执行: spa
- var optional :String? = "ok good";//注意?与=号之间有空格?号紧贴最后一个字母不能有空格
- println(optional)
输出为: .net
ok good 翻译
与
- var optional :String?//注意?与=号之间有空格?号紧贴最后一个字母不能有空格
- println(optional)
输出为:
nil 指针
来看下!号,官方释为隐式解包:主要用在一个变量/常量在定义瞬间完成以后值必定会存在的状况。这主要用在类的初始化过程当中。 code
官风例子:
- let possibleString: String? = "An optional string."
- println(possibleString!) // requires an exclamation mark to access its value
- // prints "An optional string."
-
- let assumedString: String! = "An implicitly unwrapped optional string."
- println(assumedString) // no exclamation mark is needed to access its value
实说话,你照这个例子运行,还真看不出什么,得不出什么结论。所以我本身Z磨着,试着理解一个英文翻译。再本身操刀练习。得出下面的一些结论。
- var optionVariables:String? //?至关于下面这种写法的语法糖
- //var optionVariables : Optional<Int>
- let value = optionVariables?.hashValue
- /*
- optionVariables是可选类型的字符串,若是optionVariables是nil,则hashValue也为nil
- 若是optionVariables不为nil,hashValue就是strValue字符串的哈希值
- 到这里咱们看到了?的两种使用场景:
- 1.声明Optional值变量
- 2.用在对Optional值操做中,用来判断是否能响应后面的操做
- */
-
- //对于可选类型变量,不能直接进行操做,不然会报错
- //let hashval = optionVariables.hashValue //'String?' does not have a member named 'hashValue'
- //所以要访问值就须要解包,解包有两种
- //第一种:使用if let/var xxx =
- if let hv = optionVariables
- {
- //run ok;
- }
-
- //第二种:使用!号
- let hv = optionVariables!.hashValue
-
- //这里的!表示“我肯定这里的的strValue必定是非nil的,尽情调用吧” ,好比这种状况:
-
- if optionVariables {
- let hashv = optionVariables!.hashValue
- }
- //{}里的optionVariables必定是非nil的,因此就能直接加上!,强制拆包(unwrap)并执行后面的操做
凡在变量或常量后加上?的都是一个可选变量/可选常量
凡在变量或常量后加上!的都是隐式可选变量/常量,有点难理解,首先该变量或常量知足可选类型,其主要是可被当生通常的变量/常量来使用,而不须要每次都验证是否有值。
注:若是一个隐式解包的可选类型不包含一个实际值,那么对它的访问会抛出一个运行时错误。在变量/常量名后面加!的状况也是同样的。
- var possibleString: String? = "An optional string."
- //possibleString = nil
- println(possibleString) // possibleString 为可选变量,须要使用!来访问的值
分析:首先 possibleString 因后面带上了?说明这是一个可选的,同时前面加上var为变量,因此这是一个可选类型的变量。其可选值为 "An optional string." 再来看执行println后,能够看出输出为 An optional string. 这点很明显。再来看一下把println这句改一下改成 (即在可选变量后面加上一个!号。)
- <span style="font-size:18px;">println(possibleString!) // possibleString 为可选变量,须要使用!来访问的值</span>
这里结果与没有加!号时是彻底同样的,输出为An optional string.
好,如今重点来了,这是很关键的一个测试。把possibleString = nil 这句注释放开让其动行,再分别来看一下println带!和不带!的状况:
状况一:不带!号时,输出为nil .
- <span style="font-size:18px;"> var possibleString: String? = "An optional string."
- possibleString = nil
- println(possibleString) </span>
状况二:再来看一下带!号
- <span style="font-size:18px;"> var possibleString: String? = "An optional string."
- possibleString = nil
- println(possibleString!) // possibleString 为可选变量,须要使用!来访问的值</span>
这时运行到这句println就会crash了。会报
fatal error: Can't unwrap Optional.None
错误。
在状况一时,为何不会报错,是由于这是一个可选变量当变量为nil时,自动验证是否有可选的值,有则使用可选值,在状况二,加上!访问符来访问possibleString 变量,但因为possibleString设为了nil (等价于var possibleString: String?) 其并无包含一个实际值,因此抛异常.一样对于下面使用!号来声明的也同样道:
- <span style="font-size:18px;"> var assumedString: String! = "An implicitly unwrapped optional string."
- assumedString = nil
- println(assumedString!)</span>
一样会报:fatal error: Can't unwrap Optional.None
若是你定义了一个可选类型而且没有给予初始值的时候,会默认设置为nil
var surveyAnswer: String? // 初自动设置为nil
注: Swift 的nil不一样于Object-C中的nil. Object-C中,nil是一个指针指向不存在的对象。Swift中,nil不是指针而是一个特定类型的空值。任何类型的可选变量均可以被设为nil,不光是指针。
在swift中做何变量/常量的声明都必须带有初始值,不然就要声明为可选型。
即var btn:UIButton 这样是编译报错的。因些必须改成带初始化的如:
var btn2 :UIButton = UIButton()
或者使用? 和! 来约束。
所以经常声明可选或隐式可选变量如:
var btn :UIButton? // 默认btn = nil
var edt :UITextField! // 默认edt = nil
至于何时使用?什么状况下使用!号来约束变量,我尚未悟出真真原理。
所以借助于本身的几回验证来帮助你们理解。
- <span style="font-size:18px;"> var btn :UIButton? // 默认btn = nil
- var btn2 :UIButton = UIButton() // 默认实例化一个对对象
- var btn3 :UIButton! // 默认btn = nil
- //var btn4 :UIButton //编译期报错 要求进行初始化操做
- //运行会报错fatal error: Can't unwrap Optional.None 因btn = nil
- btn!.tintColor = UIColor.blackColor()
- btn!.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
- btn!.frame = CGRectMake(0,0,50,40)
-
- //运行正常
- btn2.tintColor = UIColor.blackColor()
- btn2.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
- btn2.frame = CGRectMake(0,0,50,40)
-
- //运行会报错fatal error: Can't unwrap Optional.None 因btn3 = nil
- btn3.tintColor = UIColor.blackColor()
- btn3.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
- btn3.frame = CGRectMake(0,0,50,40)</span>
所以为了运行期不crash能够改成以下:
- <span style="font-size:18px;"> var btn :UIButton? // 默认btn = nil
- var btn2 :UIButton = UIButton() // 默认实例化一个对对象
- var btn3 :UIButton! // 默认btn = nil
-
- //运行会报错fatal error: Can't unwrap Optional.None 因btn = nil
- if var tmpbtn = btn
- {
- btn!.tintColor = UIColor.blackColor()
- btn!.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
- btn!.frame = CGRectMake(0,0,50,40)
- }
-
- //运行正常
- btn2.tintColor = UIColor.blackColor()
- btn2.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
- btn2.frame = CGRectMake(0,0,50,40)
-
- //运行会报错fatal error: Can't unwrap Optional.None 因btn3 = nil
- if var tmpbtn = btn
- {
- btn3.tintColor = UIColor.blackColor()
- btn3.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
- btn3.frame = CGRectMake(0,0,50,40)
- }</span>
或者
- <span style="font-size:18px;"> var btn :UIButton? // 默认btn = nil
- var btn2 :UIButton = UIButton() // 默认实例化一个对对象
- var btn3 :UIButton! // 默认btn = nil
-
- //运行会报错fatal error: Can't unwrap Optional.None 因btn = nil
- if btn
- {
- btn!.tintColor = UIColor.blackColor()
- btn!.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
- btn!.frame = CGRectMake(0,0,50,40)
- }
-
- //运行正常
- btn2.tintColor = UIColor.blackColor()
- btn2.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
- btn2.frame = CGRectMake(0,0,50,40)
-
- //运行会报错fatal error: Can't unwrap Optional.None 因btn3 = nil
- if btn3
- {
- btn3.tintColor = UIColor.blackColor()
- btn3.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
- btn3.frame = CGRectMake(0,0,50,40)
- }</span>
注:若是一个可选类型存在没有值的可能的话,不该该使用解包(隐式)可选类型。这种状况下,必定要使用正常的可选类型。
这句话我我的是这样理解的,如var view:UIView。当个人整个应用中或整个类中不可能存在view = nil的状况时能够设置为var view:UIView! 不然就可声明为var view:UIView?