Pointer and malloc in Swift
You can use malloc
from Swift, it returns a "raw pointer":
var p: [UnsafeMutableRawPointer?] = Array(repeating: nil, count: 10000)
var allocatedMB = 0
p[allocatedMB] = malloc(1048576)
memset(p[allocatedMB], 0, 1048576)
Alternatively, use UnsafeMutablePointer
and itsallocate
and initialize
methods:
var p: [UnsafeMutablePointer<UInt8>?] = Array(repeating: nil, count: 10000)
var allocatedMB = 0
p[allocatedMB] = UnsafeMutablePointer.allocate(capacity: 1048576)
p[allocatedMB]?.initialize(to: 0, count: 1048576)
Free C-malloc()'d memory in Swift?
Swift does not manage memory that is allocated with malloc()
, you have to free the memory eventually:
let ret = the_function("something") // returns pointer to malloc'ed memory
let str = String.fromCString(ret)! // creates Swift String by *copying* the data
free(ret) // releases the memory
println(str) // `str` is still valid (managed by Swift)
Note that a Swift String
is automatically converted to a UTF-8
string when passed to a C function taking a const char *
parameter
as described in String value to UnsafePointer<UInt8> function parameter behavior.
That's why
let ret = the_function(("something" as NSString).UTF8String)
can be simplified to
let ret = the_function("something")
Converting Objective-C malloc to Swift
malloc
and free
actually work fine in Swift; however, the UnsafeMutablePointer
API is more "native". I'd probably use Data
's bytesNoCopy
for better performance. If you want, you can use Data(bytes:count:)
, but that will make a copy of the data (and then you need to make sure to deallocate the pointer after making the copy, or you'll leak memory, which is actually a problem in the Objective-C code above since it fails to free
the buffer).
So, something like:
func prepareEndPacket() -> Data {
let count = PACKET_SIZE + 5
let buf = UnsafeMutablePointer<UInt8>.allocate(capacity: count)
PrepareEndPacket(buf)
return Data(bytesNoCopy: buf, count: count, deallocator: .custom { ptr, _ in
ptr.deallocate()
})
}
By using bytesNoCopy
, the Data
object returned is basically a wrapper around the original pointer, which will be freed by the deallocator when the Data
object is destroyed.
Alternatively, you can create the Data
object from scratch and get a pointer to its contents to pass to PrepareEndPacket()
:
func prepareEndPacket() -> Data {
var data = Data(count: PACKET_SIZE + 5)
data.withUnsafeMutableBytes { (ptr: UnsafeMutablePointer<UInt8>) in
PrepareEndPacket(ptr)
}
return data
}
This is slightly less efficient, since the Data(count:)
initializer will initialize all the Data
's bytes to zero (similar to using calloc
instead of malloc
), but in many cases, that may not make enough of a difference to matter.
Swift: Interoperability of UnsafeMutablePointer.deallocate(capacity:) with free()
Documentation is unclear about this, but testing suggests interoperability.
Using malloc()
in C, then calling deallocate()
in Swift and trying to free()
the pointer in C (or vice versa) will result in a run-time error, yet the code will run fine if only one of deallocate()
or free()
is used, but not both.
Similarly, allocating a structure in Swift, then using deallocate()
in Swift and free()
in C (or the other way around) will also result in a run-time error.
It is also OK to use free()
in Swift as suggested by @jtbandes. In fact, this approach might be safer than calling deallocate()
.
As for documentation, see https://developer.apple.com/reference/swift/unsafemutablepointer.
Also, you can dig through the UnsafeMutablePointer
's source code here: https://github.com/apple/swift/blob/master/stdlib/public/core/UnsafePointer.swift.gyb
I haven't had time to figure out the implementation yet.
Pointer being freed was not allocated [Swift]
The problem is that the buffer is allocated only once, but free'd every
time when
String(bytesNoCopy: buffer, length: numberOfBytesRead, encoding: .ascii, freeWhenDone: true)
is called. Here is a short self-contained example demonstrating the problem:
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: 4)
memcpy(buffer, "abcd", 4)
var s = String(bytesNoCopy: buffer, length: 4, encoding: .ascii, freeWhenDone: true)
// OK
s = String(bytesNoCopy: buffer, length: 4, encoding: .ascii, freeWhenDone: true)
// malloc: *** error for object 0x101d8dc40: pointer being freed was not allocated
Using freeWhenDone: false
would be one option to solve the problem, but note
that you have to free the buffer eventually.
An alternative is to use an Array
(or Data
) as buffer, this is automatically
released when the function returns. Example:
var buffer = [UInt8](repeating: 0, count: maxReadLength)
while inputStream.hasBytesAvailable {
let numberOfBytesRead = inputStream.read(&buffer, maxLength: maxReadLength)
if numberOfBytesRead < 0 {
break
}
if let receivedMsg = String(bytes: buffer[..<numberOfBytesRead], encoding: .ascii) {
// ...
}
}
What is the swift equivalent of this cast?
The first two of those are of type size_t
, which maps to Uint
in Swift, and the last is GLubyte
, which maps to UInt8
. This code will initialize spriteData
as an array of GLubyte
, which you could pass to any C function that needs an UnsafeMutablePointer<GLubyte>
or UnsafePointer<GLubyte>
:
let width = CGImageGetWidth(spriteImage)
let height = CGImageGetHeight(spriteImage)
var spriteData: [GLubyte] = Array(count: Int(width * height * 4), repeatedValue: 0)
What do you need to do with spriteData
?
Related Topics
Removing Scheduled Local Notification
Why Are Implicitly Unwrapped Variables Now Printing Out as Some(...) in Swift 4.1
Firebase Data Structure Best Practice for User Interaction
Swift String Indexing Combines "\R\N" as One Char Instead of Two
How to Refer to a Global Type from Within a Class That Has a Nested Type with The Same Name
How to Get The .Mlmodel to Be Used in Swift Playground
Converting Local Realms to Synced Realm
How to Cache Cells and Also Reuse Cells in a Collectionview That Has Avplayers Embedded in Each Cell
Problem with Swiftui and Foreach on Xcode Playground
Why Swift Disallows Weak Reference for Non-Optional Type
Macos Swift Master-Detail Delegate/Protocol Not Working
[Bool]' to 'Nil' Always Returns True - Issue in Swiftui
Swift Package: Ld: Warning: Dylib Was Built for Newer Macos Version (11.0) Than Being Linked (10.15)
iOS-Charts Error: Thread1: Exc_Bad_Access (Code=2, Address=0X2A0C220)
3 Component Dynamic Multi UIpickerview Swift
I Opened My App in Xcode 10 and Now I Have Errors in 9.4.1: Sdkapplicationdelegate (Facebookcore)