注重安全的swift中变量声明时要表明是否可变,不变用<code>let</code>,可变用<code>var</code>。然而由于swift设计之初就要考虑兼容OC的这个历史包袱,很多类型都沿用了OC的类型。只有几个基础类型重写声明成了值类型(struct),比如:<code>String</code>,<code>Array</code>。
引用类型的<code>let</code>和值类型的<code>let</code>在逻辑上有着根本的不同。值类型的不可变就如字面意义,数据不能被更改;而引用类型的不可变只要保证指向的实例不变就可以了,实例本身的属性是可以改变的。
一些原有的OC的foundation表示数据的引用类型在swift的行为就和期待的不同了,比如:
let date = NSDate()
date.addingTimeInterval(1000)
这样的写法是可以编译通过的。然而确和我们期望的结果不同。我们声明了一个不可变的日期,然而在<code> addingTimeInterval </code>后日期已经被改变了。
所以在3.0中把原有的很多表示数据的引用类型在增加了对应的值类型。
更改的如下:
Value Type | Class Type |
---|---|
AffineTransform | NSAffineTransform |
CharacterSet | NSCharacterSet, NSMutableCharacterSet |
Date | NSDate |
DateComponents | NSDateComponents |
Data | NSData, NSMutableData |
IndexSet | NSIndexSet, NSMutableIndexSet |
IndexPath | NSIndexPath |
Notification | NSNotification |
PersonNameComponents | NSPersonNameComponents |
URL | NSURL |
URLComponents | NSURLComponents |
URLQueryItem | NSURLQueryItem |
UUID | NSUUID |
在swift中相关的api返回类型也做了对应的更改。比如常见的<code> cellForRow </code>方法:
func cellForRow(at indexPath: IndexPath) -> UITableViewCell?
原来的参数类型是NSIndexPath,现在则改为了IndexPath。
和原来的OC的类型映射和原来的逻辑一样,类型转换直接使用<code> as </code>
let ocString = NSString(string: "xxx")
let swiftString: String = ocString as String
let swiftIndex = IndexPath(row: 1, section: 1)
let ocIndex = swiftIndex as NSIndexPath
需要强调的是,两者之间的转换是有成本的。swift中并没有真正完全的实现一套数据存储逻辑。只是内部保存了对oc对象的引用,使得swift api访问时行为逻辑和值类型一致,包括copy on write。
如下图所示,当执行<code> var otherData = data </code>后,其实指向的是同一个引用类型的实例。
欢迎关注我的微博:@没故事的卓同学