利用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纷纷释放内存

 

posted @ 2021-08-16 15:57  zbblogs  阅读(176)  评论(0编辑  收藏  举报