2015-09-07 58 views
3

我正在實施一個純Swift NSData替代方案。下面是我的Swift 2代碼的一部分。據我所知,Data實例取消初始化並沒有destroy()dealloc()字節block緩衝區指向。 那麼,有沒有辦法在緩衝區指針上調用destroydealloc(),以防止Data實例取消初始化之前的內存泄漏?發佈UnsafeMutableBufferPointer <UInt8>值

public struct Data: DataContainer { 
    public typealias Block = UInt8 
    public var blocks: UnsafeMutableBufferPointer<Block> 

    public init(bytes: UnsafeMutablePointer<Block>, length: Int) { 
     // copy bytes 
     let bytesCopy = UnsafeMutablePointer<Block>.alloc(length) 
     bytesCopy.initializeFrom(bytes, count: length) 
     // init byte blocks 
     self.blocks = UnsafeMutableBufferPointer<Block>(start: bytesCopy, count: length) 
    } 
} 

回答

5

你可以通過使用class來解決這個問題。 一個實例如何可以做到這一點在 Friday Q&A 2015-04-17: Let's Build Swift.Array給出:

破壞可以通過使用class,其提供deinit來解決。指針可以在那裏銷燬。 class不具有值語義, 但是我們可以通過使用classstruct的實施,並露出作爲struct外部接口到 陣列解決這個問題。這看起來是這樣的:

class ArrayImpl<T> { 
    var ptr: UnsafeMutablePointer<T> 

    deinit { 
     ptr.destroy(...) 
     ptr.dealloc(...) 
    } 
} 

struct Array<T> { 
    var impl: ArrayImpl<T> 
} 

然後寫上Array方法是期待的實現,取決於 ArrayImpl,其中真正的工作就完成了。

運用這一方法,您的問題可能大致是這樣的:

private class DataImpl { 
    typealias Block = UInt8 
    var blocks: UnsafeMutableBufferPointer<Block> 

    init(bytes: UnsafeMutablePointer<Block>, length: Int) { 
     // copy bytes 
     let bytesCopy = UnsafeMutablePointer<Block>.alloc(length) 
     bytesCopy.initializeFrom(bytes, count: length) 
     // init byte blocks 
     self.blocks = UnsafeMutableBufferPointer<Block>(start: bytesCopy, count: length) 
    } 

    deinit { 
     print("deinit") 
     blocks.baseAddress.destroy(blocks.count) 
     blocks.baseAddress.dealloc(blocks.count) 
    } 
} 

struct Data { 
    typealias Block = UInt8 
    private var impl : DataImpl 

    init(bytes: UnsafeMutablePointer<Block>, length: Int) { 
     impl = DataImpl(bytes: bytes, length: length) 
    } 
} 

一個簡單的測試表明,該工程預期,數據公佈 當變量超出範圍:

var bytes : [UInt8] = [1, 2, 3, 4] 
do { 
    let data = Data(bytes: &bytes, length: bytes.count) 
} 
print("finished") 

輸出:

 
deinit 
finished 
+0

非常感謝你,你的回答幫我節省我的時間 – b1nary

+0

@ b1nary:不客氣。 - 順便說一句,不是你自己的內存分配,你可以使用'[UInt8]'數組作爲後備存儲,然後自動處理解除分配。 –

1

感謝@Martin R爲他的answer。 我添加了class AutoreleasingMutableBufferPointer<T>作爲容器和釋放器struct UnsafeMutableBufferPointer<T>。 這裏是工作代碼:

public class AutoreleasingMutableBufferPointer<T> { 
    public var buffer: UnsafeMutableBufferPointer<T> 

    public init(start pointer: UnsafeMutablePointer<T>, count length: Int) { 
     self.buffer = UnsafeMutableBufferPointer<T>(start: pointer, count: length) 
    } 

    public init(buffer: UnsafeMutableBufferPointer<T>) { 
     self.buffer = buffer 
    } 

    deinit { 
     self.buffer.baseAddress.destroy(buffer.count) 
     self.buffer.baseAddress.dealloc(buffer.count) 
    } 
} 

public struct Data: DataContainer { 
    public typealias Block = UInt8 
    public var blocks: AutoreleasingMutableBufferPointer<Block> 
} 

extension Data { 
    public init(bytes: UnsafeMutablePointer<Block>, length: Int) { 
     let bytesCopy = UnsafeMutablePointer<Block>.alloc(length) 
     bytesCopy.initializeFrom(bytes, count: length) 
     self.blocks = AutoreleasingMutableBufferPointer<Block>(start: bytesCopy, count: length) 
    } 
} 
+0

由於您正在*複製'Data'構造函數中的數據,因此不需要指定* mutable *指針作爲參數,我將其定義爲'public init(bytes:UnsafePointer ,length:Int)'。然後,您甚至可以從常量數組​​創建一個'Data':'let bytes:[UInt8] = [1,2,3,4];讓data = Data(字節:字節,長度:bytes.count)'。 –