利用ManagedBuffer<Header, Element>实现自定义数组类型
我们知道swift中的数组类型为Array<Element>,它用于存储不同类型的元素,并且它是一个结构体struct,因此它是一个值类型,拥有写时拷贝特性。apple为我们提供了ManagedBuffer,用于存储不同类型的元素到缓冲区指针中,因此我们可以通过ManagedBuffer自己实现一个数组存储类。
一般我们需要子类化ManagedBuffer,因为它是class类型,因此子类也必须是class类型,我们需要做的仅仅是在子类的析构函数中,回收其缓冲区指针指向的一块儿内存。
首先我们定义其子类,MyListBuffer
// Header: Int(用于存储当前缓冲列表元素总个数) class MyListBuffer<Element>: ManagedBuffer<Int, Element> { deinit { self.withUnsafeMutablePointers { (hPtr: UnsafeMutablePointer<Int>, liPtr: UnsafeMutablePointer<Element>) -> Void in print("MyListBuffer deinit count: \(hPtr.pointee)") liPtr.deinitialize(count: hPtr.pointee) // 缓冲区对象析构前,需要将其存储的元素销毁 } } }
接下来我们定义自己的数组类MyList
struct MyList<Element> { /// 定义一个缓冲区,用于存储列表元素 private var _buffer: MyListBuffer<Element> /// 默认缓冲区大小 private let _capacity = 20 init() { // 初始化一个默认缓冲区大小的缓冲区 _buffer = MyListBuffer<Element>.create(minimumCapacity: _capacity, makingHeaderWith: { (bf: ManagedBuffer<Int, Element>) -> Int in // 你可以在这里向缓冲区中添加默认元素,并返回当前缓冲区的元素个数,这里没有默认元素,因此缓冲区元素个数返回0 return 0 // 返回Header初始值(即当前缓冲区的元素个数) }) as! MyListBuffer<Element> // 因为create方法返回的是ManagedBuffer<Int, Element>类型,因此需要做一下强转 } init(capacity: Int) { // 初始化一个指定缓冲区大小的缓冲区 _buffer = MyListBuffer<Element>.create(minimumCapacity: capacity, makingHeaderWith: { (bf: ManagedBuffer<Int, Element>) -> Int in // 你可以在这里向缓冲区中添加默认元素,并返回当前缓冲区的元素个数,这里没有默认元素,因此缓冲区元素个数返回0 return 0 // 返回Header初始值(即当前缓冲区的元素个数) }) as! MyListBuffer<Element> // 因为create方法返回的是ManagedBuffer<Int, Element>类型,因此需要做一下强转 } init(_ list: [Element]) { // 初始化一个默认缓冲区大小的缓冲区 _buffer = MyListBuffer<Element>.create(minimumCapacity: _capacity + list.count, makingHeaderWith: { (bf: ManagedBuffer<Int, Element>) -> Int in guard list.count > 0 else { return 0 } return bf.withUnsafeMutablePointers { (hPtr: UnsafeMutablePointer<Int>, liPtr: UnsafeMutablePointer<Element>) -> Int in // 注意:在初始化中bf的hPtr.pointee == 4634837041(这时的hPtr是未初始化) var len = 0 for i in list.indices{ (liPtr + i).initialize(to: list[i]) len += 1 } return len // 返回当前缓冲区元素个数,初始化hPtr } }) as! MyListBuffer<Element> // 因为create方法返回的是ManagedBuffer<Int, Element>类型,因此需要做一下强转 } }
接下来我们扩展MyList,使其实现Collection协议,这样是为了让MyList实现集合相关的方法
// 实现集合功能 extension MyList: Collection{ var startIndex: Int{ 0 } var endIndex: Int{ _buffer.header } var count: Int{ _buffer.header } func makeIterator() -> MyListIterator<MyList<Element>> { return MyListIterator(self) } subscript(position: Int) -> Element { guard position < count else { fatalError("Index out of range") } return _buffer.withUnsafeMutablePointerToElements { (listPtr: UnsafeMutablePointer<Element>) -> Element in return listPtr[position] } } func index(after i: Int) -> Int { return i + 1 } mutating func append(_ el: Element) { if !isKnownUniquelyReferenced(&_buffer) { // _buffer存在多个实例强引用,说明当前MyList结构体发生了深度拷贝,而_buffer是class类型实例,所以_buffer只会进行浅拷贝,导致存在两个MyList结构体实例强引用一个_buffer实例 // 所以我们需要给新拷贝的MyList实例的_buffer,手动进行深拷贝,确保每个MyList实例都有各自的缓冲区实例,两个MyList实例在各自对缓存区添加或删除元素时,不会互相影响 _buffer = _clone() print("拷贝缓冲区") } if count == _buffer.capacity { // 需要扩容 _buffer = _resize(size: count + _capacity) print("扩容") } _buffer.withUnsafeMutablePointers { (hPtr: UnsafeMutablePointer<Int>, liPtr: UnsafeMutablePointer<Element>) in (liPtr + hPtr.pointee).initialize(to: el) hPtr.pointee += 1 } } @discardableResult mutating func remove(at: Int) -> Element { guard 0 <= at && at < count else { fatalError("at out of range") } if !isKnownUniquelyReferenced(&_buffer){ // 当前结构体被拷贝了,因此在操作_buffer之前,需要将_buffer拷贝一份 _buffer = _clone() print("拷贝缓冲区") } return _buffer.withUnsafeMutablePointers { (hPtr: UnsafeMutablePointer<Int>, liPtr: UnsafeMutablePointer<Element>) -> Element in // 删除数组元素,就是将被删除元素后面的元素前移,并释放最后一个位置指针初始值 let element: Element = (liPtr + at).pointee for i in at..<count-1{ (liPtr + i).pointee = (liPtr + i + 1).pointee } (liPtr + (count - 1)).deinitialize(count: 1) hPtr.pointee -= 1 // 数组个数-1 return element } } mutating func removeAll(keepingCapacity keepCapacity: Bool = false) { if !isKnownUniquelyReferenced(&_buffer) { // 当前结构体被拷贝了,因此在操作_buffer之前,需要将_buffer拷贝一份 _buffer = _clone() print("拷贝缓冲区") } _buffer.withUnsafeMutablePointers { (hPtr: UnsafeMutablePointer<Int>, liPtr: UnsafeMutablePointer<Element>) in liPtr.deinitialize(count: count) hPtr.pointee = 0 } if !keepCapacity { _buffer = MyListBuffer<Element>.create(minimumCapacity: _capacity, makingHeaderWith: { (bf: ManagedBuffer<Int, Element>) -> Int in return 0 }) as! MyListBuffer<Element> } } }
其中我们实现了func makeIterator() -> Self.Iterator方法,我们创建了一个自己的迭代器对象,用于遍历数组元素。当然你也可以使用默认的迭代器,不需要实现该方法。
struct MyListIterator<List> where List: Collection { typealias Element = List.Element // 当前迭代器遍历的位置 private var _position: List.Index private var _list: List init(_ list: List) { _list = list _position = list.startIndex } } extension MyListIterator: IteratorProtocol{ mutating func next() -> List.Element? { guard _position < _list.endIndex else { return nil } let el = _list[_position] _list.formIndex(after: &_position) return el } }
实现数组缓冲区元素的拷贝与扩容
// 缓冲区扩容 extension MyList { /// 缓冲区扩容 private func _resize(size: Int) -> MyListBuffer<Element>{ return _buffer.withUnsafeMutablePointerToElements { (oldLiPtr: UnsafeMutablePointer<Element>) -> MyListBuffer<Element> in let oldSize = self.count return MyListBuffer<Element>.create(minimumCapacity: size) { (bf: ManagedBuffer<Int, Element>) -> Int in return bf.withUnsafeMutablePointers { (hPtr: UnsafeMutablePointer<Int>, liPtr: UnsafeMutablePointer<Element>) -> Int in // 将实例从初始化的源内存(oldLiPtr)移动到该指针引用的未初始化内存中,使源内存(oldLiPtr)未初始化,并使该指针引用的内存初始化。 liPtr.moveInitialize(from: oldLiPtr, count: oldSize) _buffer.header = 0 // 这里的目的是,让MyListBuffer,在deinit的时候,不会将旧的缓冲区中的元素释放掉:listPtr.deinitialize(count: self.header),此时header=0 return oldSize } } as! MyListBuffer<Element> } } } // 复制缓冲区 extension MyList { /// 复制缓冲区 private func _clone() -> MyListBuffer<Element>{ return _buffer.withUnsafeMutablePointerToElements { (oldLiPtr: UnsafeMutablePointer<Element>) -> MyListBuffer<Element> in return MyListBuffer<Element>.create(minimumCapacity: _buffer.capacity) { (bf: ManagedBuffer<Int, Element>) -> Int in return bf.withUnsafeMutablePointers { (hPtr: UnsafeMutablePointer<Int>, liPtr: UnsafeMutablePointer<Element>) -> Int in // 将旧缓冲区中的元素,复制到新的缓冲区中 liPtr.initialize(from: UnsafePointer<Element>(oldLiPtr), count: self.count) return self.count } } as! MyListBuffer<Element> } } }
因为MyList是一个结构体类型,因此它会存在写时拷贝特性,但是其内部的_buffer是class类型,它不会在MyList发生拷贝的时候,自动拷贝,因此我们需要自己实现,这里我们利用了isKnownUniquelyReferenced方法,判断MyList是否发生拷贝,然后手动对_buffer拷贝,这里可以参考我的上一篇文章《判断一个AnyObject实例是否存在唯一的强引用》
接下来我们使用MyList存储一个People对象,测试一下我们的数组类型。
class People: CustomStringConvertible{ let name: String let age: Int8 init(name: String, age: Int8) { self.name = name self.age = age } deinit { print("People \(self) deinit") } var description: String{ "name:\(name), age:\(age)" } }
var list = MyList<People>(capacity: 2) list.append(People(name: "drbox1", age: 20)) list.append(People(name: "drbox2", age: 21)) list.append(People(name: "drbox3", age: 22)) list.append(People(name: "drbox4", age: 23)) // 超出capacity,执行扩容 var list2 = list let p = list2.remove(at: 0) // list2发生写时拷贝 print("被删除的元素: \(p)") // 遍历数组 for pp in list { print("list: \(pp)") } for pp in list2 { print("list2: \(pp)") }
打印结果:
MyListBuffer deinit count: 0 扩容 拷贝缓冲区 被删除的元素: name:drbox1, age:20 list: name:drbox1, age:20 list: name:drbox2, age:21 list: name:drbox3, age:22 list: name:drbox4, age:23 list2: name:drbox2, age:21 list2: name:drbox3, age:22 list2: name:drbox4, age:23 MyListBuffer deinit count: 3 MyListBuffer deinit count: 4 People name:drbox1, age:20 deinit People name:drbox2, age:21 deinit People name:drbox3, age:22 deinit People name:drbox4, age:23 deinit
分析打印结果:第一行是因为执行了_buffer拷贝,相当于重新创建了一个_buffer对象,这个新的对象将原_buffer中存储的元素内存地址移动到当前_buffer指针下,并释放了原指针。因此在原指针执行析构时,打印的count = 0
第三行,是删除元素导致了写时拷贝,因此这里对_buffer进行了拷贝
从遍历两个数组对象的元素可以看出,_buffer的拷贝成功,各自维护自己的元素列表
最后在两个数组对象释放后,开始对各自的_buffer中的元素进行释放,因此数组中的元素对象People纷纷释放内存