详解Swift中Optional

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
查看查看230 回复回复6 收藏收藏 分享淘帖 转播转播 分享分享 微信
查看: 230|回复: 6
收起左侧

详解Swift中Optional

[复制链接]
firefighter 发表于 2016-9-5 12:35:05 | 显示全部楼层 |阅读模式
快来登录
获取最新的苹果动态资讯
收藏热门的iOS等技术干货
拷贝下载Swift Demo源代码

详解Swift中Optional

详解Swift中Optional - 敏捷大拇指 - 详解Swift中Optional





1、Optional

Swift中的Optional作为一种类型,既可以存储一个值,也可以为空(也就是swift里的nil),通常在类型后面加一个?表示它是Optional类型的:

[Swift] 纯文本查看 复制代码
var number: Int? = 32


其实?只不过是一个语法糖,Optional的实际类型是一个enum:

[Swift] 纯文本查看 复制代码
enum Optional<T>: _Reflectable, NilLiteralConvertible {
    case None
    case Some(T)
    //...
}


上面的var number: Int? = 32 也就可以表示为:

[Swift] 纯文本查看 复制代码
var numbet: Optional<Int> = 32


当然我们习惯上更习惯于表示为 Int?




2、Optional的作用

一个Optional对象只存在两种状态:包含一个值,或者为空,我们都可以通过解包(unwrap)来获取。下面一段出自The Swift Programming Language (Swift 3)

The concept of optionals doesn’t exist in C or Objective-C. The nearest thing in Objective-C is the ability to return nil from a method that would otherwise return an object, with nil meaning “the absence of a valid object.” However, this only works for objects—it doesn’t work for structures, basic C types, or enumeration values. For these types, Objective-C methods typically return a special value (such as NSNotFound) to indicate the absence of a value. This approach assumes that the method’s caller knows there is a special value to test against and remembers to check for it. Swift’s optionals let you indicate the absence of a value for any type at all, without the need for special constants.


Swift通过引入Optional解决了Objective-C中“有”与“无”的问题,使代码的安全性得到了很大的提高,同时我们也应该知道,Swift是一种类型安全的语言。

在某些场景下,Optional能起到很大的作用:

  • 当一些属性值可以为空时,比如一个Person类中,middleName、spouse这类的属性都可以为空
  • 当一个方法可以返回空值,比如类型转换函数,官方文档的例子

[Swift] 纯文本查看 复制代码
//try to convert a String into an Int
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber is inferred to be of type "Int?", or "optional Int"
// 如果possibleNumber 是“hello”,则转换不会成功,就会返回nil

  • 如果在一个字典中,使用key获取对应的value时,返回的也应该是Optional的值,因为你也可能找不到key对应的value,此时返回nil
  • 一个方法可以返回一个值,如果方法内部产生了错误,也可以什么都不返回
  • Delegate 属性(不总是需要被赋值)
  • class中weak 类型的属性,他们所指向的值可以为空
  • 一个大的资源可以随时被释放,以节约空间,所以正常情况下都是空的,只有使用时才会请求赋值。





3、Optional Binding

出于类型安全的考虑,我们不能再把Optional当作Boolean值处理。像下面这条语句在Swift中会遇到编译错误:

[Swift] 纯文本查看 复制代码
var myString: String? = "Hello"
if myString {
    print(myString)
}


但是你可以通过==和!=,将Optional值和nil做比较来判断它是否包含一个值。如果不包含任何值,则为空。

[Swift] 纯文本查看 复制代码
if myString != nil{
    print("myString contain a string value of \(myString!)")
}


在上面的语句里,当我们确定myString包含一个值时,我们通过在myString后面添加一个!来进行强制解包(forced unwrapping),获取Optional内包含的值。

但是实际上,Swift提供了一种更加方便的形式来完成这一过程,所谓的Optional Binding,看下面的代码:

[Swift] 纯文本查看 复制代码
if let actualString = myString {
    print("myString contain a string value of \(actualString )")
} else {
    print("myString is nil")
}


上面代码的意思是,如果optional string 包含一个值,我们就把这个值赋给actualString,然后就可以在if语句里继续使用它了,所以不再需要对其进行解包了,因为actualStr这样我们就用Optinal binding 代替了强制解包(forced unwrapping)。我们也可以使用if var actualString = myString 来获取actualString,则这个actualString就是var类型的。




4、隐式解包Optional

相较于普通的Optional值,在Swift中我们还有一种特殊的Optional,在对它的成员或者方法进行访问时,编译器会自动进行解包,被称为隐式解包Optional(ImplicitlyUnwrappedOptional),在声明时,通过在类型后面添加!来告诉编译器这是一个隐式解包Optional:

[Swift] 纯文本查看 复制代码
let possisbleString: String!


隐式解包的Optional本质上与普通的Optional值并没有什么不同,只是在访问时,编译器会自动帮我们完成在变量后插入 ! 的行为:

[Swift] 纯文本查看 复制代码
let possibleString: String! = "An implicity unwrapped optional string."
let implicitString: String = possibleString //此处我们不需要!来对possibleString 进行显示解包


很显然,隐式解包的写法会带来一个潜在的危险,如果尝试访问一个为空的隐式解包Optional, 就会遇到一个runtime error。那么Swift为什么要引入隐式解包Optional呢,王巍在他的Swift Tip解释了一下:

这一切都是历史的锅。因为Object-C中Cocoa的所有类型变量都是可以指向nil的,有一部分Cocoa的API中在参数或者返回时即使被声明为具体的类型,但是还是可能在某些特定的情况下是nil, 而同时也有另一部分API永远不会接受或者返回nil。在Objective-C时,这两种情况并没有加以区别,因为在OC中向nil发送消息是允许的,结果就是什么都不会发生,而在Cocoa API从OC转为Swift的module声明的自动化工具里,是无法判定是否存在nil的可能的,因此也无法决定哪些类型应该是实际的类型,而哪些类型应该声明为Optional。

在这种自动化转换中,最简单粗暴的应对方式是全部转为 Optional,然后让使用者通过 Optional Binding 来判断并使用。虽然这是最安全的方式,但对使用者来说是一件非常麻烦的事情,我猜不会有人喜欢每次用个 API 就在 Optional 和普通类型之间转来转去。这时候,隐式解包的 Optional 就作为一个妥协方案出现了。使用隐式解包 Optional 的最大好处是对于那些我们能确认的 API 来说,我们可直接进行属性访问和方法调用,会很方便。但是需要牢记在心的是,隐式解包不意味着 “这个变量不会是 nil,你可以放心使用” 这种暗示,只能说 Swift 通过这个特性给了我们一种简便但是危险的使用方式罢了。


我们可以在类初始化时使用隐式解包Optional,官方文档里这么描述的:Unowned References and Implicitly Unwrapped Optional Properties

我们也可以像使用一个一般的Optional一样使用隐式解包Optional。

比如判断是否为空:

[Swift] 纯文本查看 复制代码
if possibleString !=nil {
    //some action
}


比如使用if let 来进行optional binding:

[Swift] 纯文本查看 复制代码
if let implicitString = possibleString {
    print(implicitString)
}


当你知道变量可能为空的时候,不要使用隐式解包Optional。如果一个变量在它的声明周期里可能包含控制,那你总是需要使用一般的Optional。




5、Optional Chaining

Optional Chaining,如同名字一样,我们可以通过一个链来安全的访问一个Optional的属性或者方法。

可以参看一个例子:

[Swift] 纯文本查看 复制代码
if let isPNG = imagePaths["star"]?.hasSuffix(".png") {
    print("The star image is in PNG format")
}


这里通过在imagePath["star"]后面添加 ? 来获取star所对应的图片路径,如果不存在就直接是nil,如果存在则返回对应的path,然后紧接着调用path的hasSuffix方法。

使用Optional Chaining可以让我们摆脱很多不必要的判断和取值,从而精简代码。




6、??的使用

当Optional解包后的值为nil时,我们可以通过使用??来设置一个默认值。

[Swift] 纯文本查看 复制代码
let defaultImagePath = "/images/default.png"
let heartPath = imagePaths["heart"] ?? defaultImagePath
print(heartPath)


如果imagePaths中没有包含"heart"对应的value,则会把defaultImagePath赋给heartPath,也就会打印出/images/default.png 。

当然了,我们也可以将??链接起来,设置多重默认值:

[Swift] 纯文本查看 复制代码
let shapePath = imagePaths["cir"] ?? imagePaths["squ"] ?? defaultImagePath


这样每一次解包值为nil时都会设置默认的值。




作者:树说

都看到这里了,就把这篇资料推荐给您的好朋友吧,让他们也感受一下。

回帖是一种美德,也是对楼主发帖的尊重和支持。

*声明:敏捷大拇指是全球最大的Swift开发者社区、苹果粉丝家园、智能移动门户,所载内容仅限于传递更多最新信息,并不意味赞同其观点或证实其描述;内容仅供参考,并非绝对正确的建议。本站不对上述信息的真实性、合法性、完整性做出保证;转载请注明来源并加上本站链接,敏捷大拇指将保留所有法律权益。如有疑问或建议,邮件至marketing@swifthumb.com

*联系:微信公众平台:“swifthumb” / 腾讯微博:@swifthumb / 新浪微博:@swifthumb / 官方QQ一群:343549891(满) / 官方QQ二群:245285613 ,需要报上用户名才会被同意进群,请先注册敏捷大拇指

嗯,不错!期待更多好内容,支持一把:
支持敏捷大拇指,用支付宝支付10.24元 支持敏捷大拇指,用微信支付10.24元

评分

参与人数 1金钱 +10 贡献 +10 专家分 +10 收起 理由
Anewczs + 10 + 10 + 10 32个赞!专家给力!

查看全部评分

转行的 发表于 2016-9-5 17:53:05 | 显示全部楼层
终于明白了语法糖的意思啦!!
代码买卖 发表于 2016-9-5 18:04:22 | 显示全部楼层
对Optional解析的透彻!
数学家 发表于 2016-9-5 18:14:40 | 显示全部楼层
王巍牛!历史的锅!以后OC不行了之后,Swift会不会把“隐式解包Optional”这一功能取消掉呢?
swifter 发表于 2016-9-5 18:25:14 | 显示全部楼层
不是我教你诈 发表于 2016-9-21 20:24:21 | 显示全部楼层
类型安全,就这么个意思啊~~~
young 发表于 2016-9-29 19:28:57 | 显示全部楼层
斯坦福那老头也说了:“Optional的实际类型是一个enum”
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

做任务,领红包。
我要发帖

分享扩散

都看到这里了,就把这资料推荐给您的好朋友吧,让他们也感受一下。
您的每一位朋友访问此永久链接后,您都将获得相应的金钱积分奖励
热门推荐

合作伙伴

Swift小苹果

  • 北京治世天下科技有限公司
  • ©2014-2016 敏捷大拇指
  • 京ICP备14029482号
  • Powered by Discuz! X3.1 Licensed
  • swifthumb Wechat Code
  •   
快速回复 返回顶部 返回列表