How to properly free NSData bytes

Hi
So If I do something like this

let url = URL(fileURLWithPath: "test.wav")
let data = try Data(contentsOf: url)
let fb = (data as NSData).bytes
let fbytes = fb.assumingMemoryBound(to: Int8.self)
fbytes.deallocate() // Crash.

How to properly do this? I need to free manually because I'm using this with a C library that streams audio in a thread so something like withUnsafePointer is not an option.

You cannot deallocate the bytes of an NSData, you must let it be freed by dropping the reference to the NSData. Additionally, NSData.bytes is unsafe in Swift and you must never ever use it.

Can you please elaborate on what your actual problem is?

Oh, I see, I've scene that being suggested in a stackoverflow post so decided to use it.
So I just basically want to get the data content as a UnsafePointer, Send it to the C function, And then I manually later create a function that deallocates it, Something like

class Streamer {
    var buffer: UnsafePointer<Int8>
    required init(buffer: UnsafePointer<Int8>) {
        self.buffer = buffer
    }
    func destroy() {
        // Deallocate the pointer here.
    }
    static func fromMemory(data: Data) -> Streamer {
        var buffer: UnsafePointer<Int8> = ... // How to create the buffer here.
        CLibStream(buffer)
        return self.init(buffer: buffer)
    }
}

So the short answer is that you can do:

var buffer: UnsafePointer<Int8> = UnsafeMutablePointer<Int8>.allocate(capacity: whatever)

to allocate the buffer, and

buffer.deallocate()

to deallocate it. However, this is extremely unsafe. Is it possible for you to bound the execution time so that you can use a withUnsafePointer function?

Sadly there is no way to do that.
So if I'll use the allocating way, How would I do it with the Data type? I'm guessing the size would come from data.count, But how would we extract the content of data and give it to the pointer?

You would use initialize(from:).

C:\Users\mohamed\projects\swift_synthizer\Sources\synthizer\stream.swift:21:9: error: instance method 'initialize(from:)' requires the types 'Int8' and 'UInt8' be equivalent
        buffer.initialize(from: data)
        ^
Swift.UnsafeMutablePointer:10:17: note: where 'Pointee' = 'Int8', 'C.Element' = 'UInt8'
    public func initialize<C>(from source: C) where Pointee == C.Element, C : Collection
                ^

Here's the code I use

    public static func fromMemory(data: Data) throws -> StreamHandle {
        var handle = syz_Handle()
        let buffer = UnsafeMutablePointer<Int8>.allocate(capacity: data.count)
        buffer.initialize(from: data)
        return self.init(handle: handle, buffer: fbytes)
    }
}

How would I go to making it accept it?

You need to change Int8 to UInt8. Also, UnsafeMutablePointer.initialize(from:) is deprecated, so you might want to use an UnsafeMutableBufferPointer instead, i.e:

let buffer = UnsafeMutableBufferPointer<UInt8>.allocate(capacity: data.count)
_ = buffer.initialize(from: data)
1 Like

Yes but I need it to be Int8 because it's a const char * I'm sending, Which swift calls UnsafePointer.

Ok, So far, I do this and it works

    public static func fromMemory(data: Data) -> StreamHandle {
        var handle = syz_Handle()
        let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: data.count)
        data.copyBytes(to: buffer, count: data.count)
        let fb = UnsafeRawPointer(buffer)
        let buf = fb.assumingMemoryBound(to: Int8.self)
        return self.init(handle: handle, buffer: buf)
    }
}