关于 ContiguousArray
,这边有喵神的文章介绍的很详细了,可以先看看这个文章。
Array
接着喵神的思路,看一下 Array
以下是从源码中截取的代码片段。
public struct Array<Element>: _DestructorSafeContainer {
#if _runtime(_ObjC)
internal typealias _Buffer = _ArrayBuffer<Element>
#else
internal typealias _Buffer = _ContiguousArrayBuffer<Element>
#endif
internal var _buffer: _Buffer
internal init(_buffer: _Buffer) {
self._buffer = _buffer
}
}
复制代码
if _runtime(_ObjC)
等价于 #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
,从这个操作也可以看出 Swift
的野心不仅仅只是替换 Objective-C
那么简单,而是往更加宽泛的方向发展。由于本次主要是研究在 iOS
下的开发,所以主要看一下 _ArrayBuffer
。
_ArrayBuffer
去掉了注释和与类型检查相关的属性和方法。
internal typealias _ArrayBridgeStorage
= _BridgeStorage<_ContiguousArrayStorageBase, _NSArrayCore>
internal struct _ArrayBuffer<Element> : _ArrayBufferProtocol {
internal init() {
_storage = _ArrayBridgeStorage(native: _emptyArrayStorage)
}
internal var _storage: _ArrayBridgeStorage
}
复制代码
可见 _ArrayBuffer
仅有一个存储属性 _storage
,它的类型 _ArrayBridgeStorage
,本质上是 _BridgeStorage
。_NSArrayCore
其实是一个协议,定义了一些 NSArray
的方法,主要是为了桥接 Objective-C
的 NSArray
。
最主要的初始化函数,是通过 _emptyArrayStorage
来初始化 _storage
。
实际上 _emptyArrayStorage
是 _EmptyArrayStorage
的实例,主要作用是初始化一个空的数组,并且将内存指定在堆上。
internal var _emptyArrayStorage : _EmptyArrayStorage {
return Builtin.bridgeFromRawPointer(
Builtin.addressof(&_swiftEmptyArrayStorage))
}
复制代码
_BridgeStorage
struct _BridgeStorage<NativeClass: AnyObject, ObjCClass: AnyObject> {
typealias Native = NativeClass
typealias ObjC = ObjCClass
init(native: Native, bits: Int) {
rawValue = _makeNativeBridgeObject(
native, UInt(bits) << _objectPointerLowSpareBitShift)
}
init(objC: ObjC) {
rawValue = _makeObjCBridgeObject(objC)
}
init(native: Native) {
rawValue = Builtin.reinterpretCast(native)
}
internal var rawValue: Builtin.BridgeObject
复制代码
_BridgeStorage
实际上区分 是否是 class、@objc
,进而提供不同的存储策略,为上层调用提供了不同的接口,以及类型判断,通过 Builtin.BridgeObject
这个中间参数,实现不同的储存策略。
The ContiguousArray type is a specialized array that always stores its elements in a contiguous region of memory. This contrasts with Array, which can store its elements in either a contiguous region of memory or an NSArray instance if its Element type is a class or @objc protocol.
If your array’s Element type is a class or @objc protocol and you do not need to bridge the array to NSArray or pass the array to Objective-C APIs, using ContiguousArray may be more efficient and have more predictable performance than Array. If the array’s Element type is a struct or enumeration, Array and ContiguousArray should have similar efficiency.
正因为储存策略的不同,特别是在class
或者 @objc
,如果不考虑桥接到 NSArray
或者调用 Objective-C
,苹果建议我们使用 ContiguousArray
,会更有效率。
Array 和 ContiguousArray 区别
通过一些常用的数组操作,来看看两者之间的区别。
append
ContiguousArray
public mutating func append(_ newElement: Element) {
_makeUniqueAndReserveCapacityIfNotUnique()
let oldCount = _getCount()
_reserveCapacityAssumingUniqueBuffer(oldCount: oldCount)
_appendElementAssumeUniqueAnd