UnsafeMutablePointer in swift as replacement for properly sized C Array in Obj-C
Normally you can just pass an array of the required type as an in-out parameter, aka
var coords: [CLLocationCoordinate2D] = []
polyline.getCoordinates(&coords, range: NSMakeRange(0, polyline.pointCount))
but that documentation makes it seem like a bad idea! Luckily, UnsafeMutablePointer
provides a static alloc(num: Int)
method, so you can call getCoordinates()
like this:
var coordsPointer = UnsafeMutablePointer<CLLocationCoordinate2D>.alloc(polyline.pointCount)
polyline.getCoordinates(coordsPointer, range: NSMakeRange(0, polyline.pointCount))
To get the actual CLLocationCoordinate2D
objects out of the mutable pointer, you should be able to just loop through:
var coords: [CLLocationCoordinate2D] = []
for i in 0..<polyline.pointCount {
coords.append(coordsPointer[i])
}
And since you don't want a memory leak, finish up like so:
coordsPointer.dealloc(polyline.pointCount)
Just remembered Array
has a reserveCapacity()
instance method, so a much simpler (and probably safer) version of this would be:
var coords: [CLLocationCoordinate2D] = []
coords.reserveCapacity(polyline.pointCount)
polyline.getCoordinates(&coords, range: NSMakeRange(0, polyline.pointCount))
Testcase failed after converting codes from Objective-C to Swift
Objective-C version of numberOfTrailingZeros
:
// Ported from OpenJDK Integer.numberOfTrailingZeros implementation
- (int32_t)numberOfTrailingZeros:(int32_t)i {
int32_t y;
if (i == 0) return 32;
int32_t n = 31;
y = i <<16; if (y != 0) { n = n -16; i = y; }
y = i << 8; if (y != 0) { n = n - 8; i = y; }
y = i << 4; if (y != 0) { n = n - 4; i = y; }
y = i << 2; if (y != 0) { n = n - 2; i = y; }
return n - (int32_t)((uint32_t)(i << 1) >> 31);
}
When translating numberOfTrailingZeros
, you changed the return value from Int32
to Int
. That is fine, but the last line of the function is not operating properly as you translated it.
In numberOfTrailingZeros
, replace this:
return n - Int((UInt((i << 1)) >> 31))
With this:
return n - Int(UInt32(bitPattern: i << 1) >> 31)
The cast to UInt32
removes all but the lower 32 bits. Since you were casting to UInt
, you weren't removing those bits. It is necessary to use bitPattern
to make this happen.
Converting a String to UnsafeMutablePointer UInt16
You have to create an array with the UTF-16 representation of the Swift
string that you can pass to the function, and on return create
a Swift string from the UTF-16 array result.
Lets assume for simplicity that the C function is imported to Swift as
func translateString(_ source: UnsafeMutablePointer<UInt16>, _ sourceLen: UnsafeMutablePointer<CInt>,
_ dest: UnsafeMutablePointer<UInt16>, _ destLen: UnsafeMutablePointer<CInt>)
Then the following should work (explanations inline):
// Create array with UTF-16 representation of source string:
let sourceString = "Hello world"
var sourceUTF16 = Array(sourceString.utf16)
var sourceLength = CInt(sourceUTF16.count)
// Allocate array for UTF-16 representation of destination string:
let maxBufferSize = 1000
var destUTF16 = Array<UInt16>(repeating: 0, count: maxBufferSize)
var destLength = CInt(destUTF16.count)
// Call translation function:
translateString(&sourceUTF16, &sourceLength, &destUTF16, &destLength)
// Create Swift string from UTF-16 representation in destination buffer:
let destString = String(utf16CodeUnits: destUTF16, count: Int(destLength))
I have assumed that the C function updates destLength
to reflect
the actual length of the translated string on return.
How to get bytes out of an UnsafeMutableRawPointer?
load<T>
reads raw bytes from memory and constructs a value of type T
:
let ptr = ... // Unsafe[Mutable]RawPointer
let i16 = ptr.load(as: UInt16.self)
optionally at a byte offset:
let i16 = ptr.load(fromByteOffset: 4, as: UInt16.self)
There is also assumingMemoryBound()
which converts from a Unsafe[Mutable]RawPointer
to a Unsafe[Mutable]Pointer<T>
, assuming that the pointed-to memory contains a value of type T:
let i16 = ptr.assumingMemoryBound(to: UInt16.self).pointee
For an array of values you can create a "buffer pointer":
let i16bufptr = UnsafeBufferPointer(start: ptr.assumingMemoryBound(to: UInt16.self), count: count)
A buffer pointer might already be sufficient for your purpose, it
is subscriptable and can be enumerated similarly to an array.
If necessary, create an array from the buffer pointer:
let i16array = Array(i16bufptr)
As @Hamish said, more information and details can be found at
- SE-0107 UnsafeRawPointer API
Converting C char array (unsafe pointer) to String
You seem unwilling to show your code, so I can't really help. But this looks just wrong:
let deviceName = UnsafeMutablePointer<Character>.alloc(64)
/* other statements in which deviceName is filled */
That is not how to get hold of a C string in Swift, and if you believe that it is a C string in Swift, you're wrong; it would need to be an array of Int8 (C characters), not Swift Character (a struct!), to be a C string.
In other words, C char (your question's title) is not Swift Character - they are nothing like one another. A C char is a small number, a Swift Character is an object in an object-oriented language that C knows nothing about!
Related Topics
Where Is the .Camera Anchorentity Located
How to Override Layout of Nstableheaderview
Separation of Function Declaration and Definition in Swift
Why No Infinite Loop in Didset
Typecasting or Initialization, Which Is Better in Swift
Smooth Transition Between 2 Scrollviews
Given a Hexadecimal String in Swift, Convert to Hex Value
How to Make Nsattributedstring Codable Compliant
Nsundomanager Casting Nsundomanagerproxy Crash in Swift Code
Getting Data from Findobjectsinbackgroundwithblock in Swift
Property Observers for Uiview Bounds and Frame React Differently
Why Can You Assign Non-Optional Values to Optional Types in Swift
Can't Use Concrete Subclass to Implement a Property in Protocol in Swift
Common Equatable Class on Swift