How to correctly initialize an UnsafePointer in Swift?
The simplest solution is using withUnsafePointer
function:
let myFont = CTFontCreateWithName("Helvetica", 12, nil)
let myGlyph = CTFontGetGlyphWithName(myFont, "a")
var myTransform = CGAffineTransformIdentity
var path = withUnsafePointer(&myTransform) { (pointer: UnsafePointer<CGAffineTransform>) -> (CGPath) in
return CTFontCreatePathForGlyph(myFont, myGlyph, pointer)
}
The initialize
is not a constructor. You would have to alloc
a new memory using UnsafePointer<T>.alloc
, then initialize
and then dealloc
. Function withUnsafePointer
does that all for you.
Note that myTransform
cannot be a constant (var
not let
) otherwise you cannot use it for an inout
param (&myTransform
).
What does `UnsafeMutablePointer.initialize()`actually do?
One reason you need initialize()
, and the only one as for now maybe, is
for ARC.
You'd better think with local scope variables, when seeing how ARC works:
func test() {
var refVar: RefType = initValue //<-(1)
//...
refVar = newValue //<-(2)
//...
//<-(3) just before exiting the loacl scope
}
For a usual assignment as (2), Swift generates some code like this:
swift_retain(_newValue)
swift_release(_refVar)
_refVar = _newValue
(Assume _refVar
and _newValue
are unmanaged pseudo vars.)
Retain
means incrementing the reference count by 1, and release
means decrementing the reference count by 1.
But, think what happens when the initial value assignment as at (1).
If the usual assignment code was generated, the code might crash at this line:
swift_release(_refVar)
because newly allocated region for a var may be filled with garbages, so swift_release(_refVar)
cannot be safely executed.
Filling the newly region with zero (null) and release
safely ignoring the null could be one solution, but it's sort of redundant and not effective.
So, Swift generates this sort of code for initial value assignment:
(for already retained values, if you know ownership model, owned by you.)
_refVar = _initValue
(for unretained values, meaning you have no ownership yet.)
swift_retain(_initValue)
_refVar = _initValue
This is initialize
.
No-releasing the garbage data, and assign an initial value, retaining it if needed.
(The above explanation of "usual assignment" is a little bit simplified, Swift omits swift_retain(_newValue)
when not needed.)
When exiting the local scope at (3), Swift just generates this sort of code:
swift_release(_refVar)
So, this is deinitialize
.
Of course, you know retaining and releasing are not needed for primitive types like Int
, so initialize
and deinitialize
may be donothing
for such types.
And when you define a value type which includes some reference type properties, Swift generates initialize
and deinitialize
procedures specialized for the type.
The local scope example works for the regions allocated on the stack, and initialize()
and deinitialize()
of UnsafeMutablePointer
works for the regions allocated in the heap.
And Swift is evolving so swift, that you might find another reason for needing initialize()
and deinitialize()
in the future, you'd better make it a habit to initialize()
and deinitialize()
all allocated UnsafeMutablePointer
s of any Pointee
types.
Initialization of 'UnsafePointerUInt8' results in a dangling pointer
Since Swift 3 it's possible to simply initialize a Data
instance with an UInt8
array.
let sendBytes:[UInt8] = [0x0, 0x0, 0x5, 0x0]
let msgData = Data(sendBytes)
How to to assign the address of a local swift variable to an UnsafeMutablePointer
You're looking for withUnsafeMutablePointer(_: _:). It takes an inout parameter of type T
and a block that takes a parameter of type UnsafeMutablePointer<T>
. It is used as such:
var i: Int = 0
withUnsafeMutablePointer(&i) { (pointer) in
f(pointer)
}
Converting an UnsafePointer with length to a Swift Array type
You can simply initialize a Swift Array
from an UnsafeBufferPointer
:
func convert(length: Int, data: UnsafePointer<Int8>) -> [Int8] {
let buffer = UnsafeBufferPointer(start: data, count: length);
return Array(buffer)
}
This creates an array of the needed size and copies the data.
Or as a generic function:
func convert<T>(count: Int, data: UnsafePointer<T>) -> [T] {
let buffer = UnsafeBufferPointer(start: data, count: count);
return Array(buffer)
}
where length
is the number of items that the pointer points to.
If you have a UInt8
pointer but want to create an [T]
array from
the pointed-to data, then this is a possible solution:
// Swift 2:
func convert<T>(length: Int, data: UnsafePointer<UInt8>, _: T.Type) -> [T] {
let buffer = UnsafeBufferPointer<T>(start: UnsafePointer(data), count: length/strideof(T));
return Array(buffer)
}
// Swift 3:
func convert<T>(length: Int, data: UnsafePointer<UInt8>, _: T.Type) -> [T] {
let numItems = length/MemoryLayout<T>.stride
let buffer = data.withMemoryRebound(to: T.self, capacity: numItems) {
UnsafeBufferPointer(start: $0, count: numItems)
}
return Array(buffer)
}
where length
now is the number of bytes. Example:
let arr = convert(12, data: ptr, Float.self)
would create an array of 3 Float
s from the 12 bytes pointed to by ptr
.
How to Initialize OpaquePointer in Swift
What the compile error is telling you is that the initialiser that takes a bit pattern returns an optional OpaquePointer
.
So you either should use it as an optional:
@State var OP: OpaquePointer? = OpaquePointer(bitPattern: 1)
Or if you're a 100% certain the opaque pointer is never nil, you can force unwrap it:
@State var OP: OpaquePointer = OpaquePointer(bitPattern: 1)!
However, if the OpaquePointer
fails to initialise, your app will crash.
Please note that a bitPattern of 1 will most certainly fail, since this should point to an address in memory.
A better way to get an OpaquePointer is to derive it from an UnsafePointer
or UnsafeMutablePointer
, so you're sure the pointer is actually pointing to the thing you want it to.
What are you trying to point to? And do you really need an OpaquePointer
? If so, I'd highly advise to not mess with pointers inside your SwiftUI view, do this stuff in a (or multiple) layers 'above' that (so either ViewModel or Model/Data).
Related Topics
How to Add Characters into Dateformatter
New Value Is Only Available in Sendasynchronousrequest - Swift
How Could I Request Text from a Website in Swift
Can the Byte Order of Double Be Safely Reversed
How Is a Global Variable Set to Private Understood in Swift
Does _Arraytype or _Arrayprotocol Not Available in Swift 3.1
Using Tvposterimage in Tvuikit for Tvos 12
Swiftui: Unexpected Animation When Using a Non @State Var
Realitykit - How to Add Motion to a Loaded Modelentity from Usdz File
How to Create Lazy Combinations
Xcode Gm: No Swift Language for Os X Command Line Tool Project
Stanford Calculator App Keeps Crashing
What Does This Mean? Variable Declared Followed by a Block Without Assignment
Auth.Auth().Currentuser.Reload() Doesn't Refresh Currentuser.Isemailverified