Swift - ?和!的学习
最近在优化一个项目的过程,过程中发现之前开发时由于刚接触 Swift
的原因,在 Swift
中的类里使用了很多 OC
的写法,比如字典数组对象会习惯性用 NSDictionary
、NSArray
来初始化,而不是用 [KeyType: ValueType]()
或是 [SomeType]()
这种类型来实例化变量。虽然在使用上没有什么问题,但看起来多少有点。。。不优雅。
当我把大部分类型都修改成 Swift
中的写法后(部分未修改是因为使用 String
类型来给文本做截取和富文本定义,实在不如 NSString
顺手,这种不顺手让我不由想起 Stack Overflow 上看到的一个评论:I thougt i already getting along well with Swift.)发现,原来一些变量是否为空的判断中,使用 Swift
里的 optional
类型会方便很多。
比如解析一个 json 数据,如果层级多而且里面每个元素都是不确定的,那么可能就需要每个层级都判一次空。而如果使用 ? 来设置当前对象为可选值,只需要在最后一层实际使用到对象值时,判一次空就 OK 了。
对于 ? 和 ! 的区别和总结,网上有很多文章,在这里就不重复造轮子了。下面就对这个 optional
的自己两个疑问做个记录。
? 和 ! 是表示两种不同的类型吗,一种是可以为空,一种不可以为空?
刚开始使用的时候没做深入了解,以为 optional
中的 ? 和 ! 和 let
声明不可变变量,var
声明可变变量。? 和 ! 是一组彼此相对只是含义不同的两个符号。但深入了解了一下,发现并不是这样,引用两段官方的文档:
You use the Optional type whenever you use optional values, even if you never type the word Optional. Swift’s type system usually shows the wrapped type’s name with a trailing question mark (?) instead of showing the full type name. For example, if a variable has the type Int?, that’s just another way of writing Optional
. The shortened form is preferred for ease of reading and writing code. The types of shortForm and longForm in the following code sample are the same:
1
2 let shortForm: Int? = Int("42")
let longForm: Optional<Int> = Int("42")
这里的意思是说当你使用 Optional
类型时的值,即使在初始化时没有用“Optional”这个单词指定类型,在 Swift 中也可用 ? 代替。即 Int?
等于 Optional<Int>
。那按照之前我的理解,是否 ! 也是某个 Not Optional 单词的代替?后面官方文档就有提到了:
When you’re certain that an instance of Optional contains a value, you can unconditionally unwrap the value by using the forced unwrap operator (postfix !). For example, the result of the failable Int initializer is unconditionally unwrapped in the example below.
意思是说 ! 是代表一种 Unconditional Unwrapping
的运算符,而并不是作为一种类型的表达。
关于 Unconditional Unwrapping
Unconditional Unwrapping
怎么理解,直译的话叫无条件展开,专业术语叫强制拆包。为什么使用 Optional
类型会需要强制拆包,如果使用 ! 运算符意味着强制拆包,那不使用 ! 时,Optional
是否还会做拆包的处理呢?
仍然回到官方文档,有这句:
The Optional type is an enumeration with two cases. Optional.none is equivalent to the nil literal.
也就是说 Optional
是一个默认带有 Optional.none
枚举类型的包装。所以使用时我们必须按官方说的:
You must unwrap the value of an Optional instance before you can use it in many contexts.
其他
基于以上的学习和理解,我们可以来解读以下一些写法:
1 | let value:NSString = nil //错误写法,未指定 Optional,所以不可以被赋值为空 |
1 | let array:NSArray = NSMutableArray.init(object: "111") |
1 | //可传空值 |
1 | let fruitDic: [String: String] = ["apple":"red","banana":"yellow"] |
-
2020-09-06
-
2020-05-30
-
2020-09-12
注意到工程里面关于权限请求这块的逻辑没有很好地管理起来,一些是用 OC 的工具类,一些是用 Swift 代码在一些
ViewController
里面单独调用,不能复用,就想封装一个 Swift 版关于权限请求的工具类,虽然这个需求在 GitHub 上搜索也有很多现成的轮子,但使用起来感觉太重,而且有些久不维护,Swift 版本更新的又快,有些接口就不好使了,索性就自己封装一个。一开始的思路也是想通过枚举来创建不同权限字段,通过静态方法来实现请求,但是蓝牙权限和定位权限需要实例化对象,设置代理。当使用
static
关键字来创建蓝牙和定位对象,当应用内有其他的业务也要使用蓝牙和定位对象时,代理响应就会有点问题。后面索性就用单例方法创建一个整体的权限管理对象,然后创建类方法,在类方法中自己调用自己。 -
2019-10-31
iOS开发者规范:以苹果开发者中心规范(Coding Guidelines for Cocoa)为标准,添加部分规范。
iOS 命名两大原则是:可读性高和防止命名冲突(通过加前缀来保证). Objective-C 的命名通常都比较长, 名称遵循驼峰式命名法. 一个好的命名标准很简单, 就是做到在开发者一看到名字时, 就能够懂得它的含义和使用方法. 另外, 每个模块都要加上自己的前缀, 前缀在编程接口中非常重要, 可以区分软件的功能范畴并防止不同文件或者类之间命名发生冲突, 比如相册模块(PhotoGallery)的代码都以 PG 作为前缀: PGAlbumViewController, PGDataManager.
-
2019-01-16
规范文档翻译自 raywenderlich.com 的编码规范
目录