Swift: Cannot convert value of type 'UnsafeMutablePointer' to expected argument type 'UnsafeMutablePointer'

Luke Pistrol  picture Luke Pistrol · Nov 2, 2016 · Viewed 20k times · Source

I have a little Problem with my Code after updating to Swift 3. I had this Code before the conversion:

extension NSData {
  func castToCPointer<T>() -> T {
    let mem = UnsafeMutablePointer<T>.alloc(sizeof(T.Type))
    self.getBytes(mem, length: sizeof(T.Type))
    return mem.move()
  }
}

And I converted it to this Code and in the 3rd line I get an Error

... Cannot convert value of type 'UnsafeMutablePointer' to expected argument type 'UnsafeMutablePointer'

extension Data {
  func castToCPointer<T>() -> T{
    let mem = UnsafeMutablePointer<T>.allocate(capacity: MemoryLayout<T.Type>.size)
    self.copyBytes(to: mem, count: MemoryLayout<T.Type>.size)
    //self.copyBytes(to: mem, count: MemoryLayout<T.Type>.size)
    return mem.move()
  }
}

Does anyone know how to get rid of this?

Answer

Martin R picture Martin R · Nov 2, 2016

copyBytes expects a UnsafeMutableBufferPointer as argument:

extension Data {
    func castToCPointer<T>() -> T {
        let mem = UnsafeMutablePointer<T>.allocate(capacity: 1)
        _ = self.copyBytes(to: UnsafeMutableBufferPointer(start: mem, count: 1))
        return mem.move()
    }
}

(allocate() takes the number of "items" as argument, not the number of bytes.)

But note that your method leaks memory, the allocated memory is deinitialized (with move()) but also has to be deallocated:

extension Data {
    func castToCPointer<T>() -> T {
        let mem = UnsafeMutablePointer<T>.allocate(capacity: 1)
        _ = self.copyBytes(to: UnsafeMutableBufferPointer(start: mem, count: 1))
        let val =  mem.move()
        mem.deallocate(capacity: 1)
        return val
    }
}

A simpler solution would be (from round trip Swift number types to/from Data):

extension Data {
    func castToCPointer<T>() -> T {
        return self.withUnsafeBytes { $0.pointee }
    }
}