How to get UnsafeRawPointer on the swift object? - swift

My app uses the native C++ lib, there is a method that takes as an argument void*
void foo(void * obj) { ... }
in swift I can call this method like this
func boo(obj: MyCustomObj) {
foo(&obj)
}
and looks like really I get a void pointer on the object, but if I try to get an UnsafeRawPointer on the object like this
func boo(obj: MyCustomObj) {
var pointer = &obj <---- Use of extraneous '&'
foo(pointer)
}
I got an error
Use of extraneous '&'
What is the problem here?
EDIT
I understood that using withUnsafe*** I can get the pointer to the data, but what to do if my method has 2 params, would it looks like this
withUnsafePointer(to: myObjFirst) {
pFirst in
withUnsafePointer(to: myObjSecond) {
pSecond in
foo(pFirst, pSecond)
}
}

The & syntax does not mean "the address of" or "pointer to" like in C. In Swift, it is an in-out expression.
These can be used to create implicit pointer conversions as a convenience, and that can seem like C's "pointer to" meaning, but it has very different rules and behaviors. For example, there is no promise that obj even has an address. It may be a tagged pointer. Passing it via an in-out expression may allocate memory and copy the value to make the call possible. Similarly, when passing a "pointer to an array," Swift will actually pass a pointer to a contiguous block of values (which may have been copied to make them contiguous) which is not the same as the actual Array struct.
It is not meaningful to say var pointer = &obj. There is no in-out reference there.
There is no general way to take long-lived pointers to objects in Swift without allocating your own memory (and this is rare). The memory model doesn't promise the kinds of lifetimes you'd need to make that sensible. If your code did compile the way you expect it to, the call to foo(pointer) would still be invalid because there's no promise that obj exists at that point and the pointer could be dangling. (There are no references to obj after the first line, so Swift can and often will destroy it, even though it's still "in scope.")
The foo(&obj) syntax is basically a shorthand for:
withUnsafePointer(to: obj) { foo($0) }
It exists to make it easier to call C functions, but it doesn't mean that Swift pointers are anything like C pointers.
For much more on Swift pointers, see Safely manage pointers in Swift from WWDC 2020.

Related

Is it possible to get the retain count of a Closure in Swift?

In Swift, Closures are reference types. Which means (I think, please correct me if I'm wrong) that they have a lifetime managed by a retain count. I can get the retain count of an object using CFGetRetainCount, but this doesn't work for Closures because they can't conform to AnyObject (or any protocol for that matter).
Before anyone jumps in and tells me I'm doing the wrong thing by trying to get the retain count of anything manually, I know. It's purely for experimentation to prove to myself that this is how Closure lifetime is managed by the runtime.
You can use CFGetRetainCount if you declare the closure as #convention(block), as this will instruct the compiler to generate an Objective-C block, which is for all intended purposes an object:
let closure: #convention(block) () -> Void = {
print("test")
}
print(CFGetRetainCount(unsafeBitCast(closure, to: CFTypeRef.self)))

Swift 2: Why is it necessary to apply ‘as!’ after getting new object by ‘copy()’?

I’ve created new SKEmitterNode object using copy() method. After that i’ve tried to write emitter.position but Xcode said «Ambiguous reference to member ‘position’». But, when i use type conversion «as! SKEmitterNode» after the «copy()», everything is ok. Can you explain me, please, why am i need to use «as!» in this case? I can’t understand this because when i check value type of «emit» variable in debugger, i can see that it’s already have the type SKEmitterNode, even without using «as! SKEmitterNode» after «copy()».
class GameScene: SKScene, SKPhysicsContactDelegate {
let bangEmitter : SKEmitterNode = SKEmitterNode(fileNamed: "MyParticle")!
func makeBang(position: CGPoint) {
// this method causes an error in second line
// but, emit is already have type SKEmitterNode, as debugger says
var emit = bangEmitter.copy()
emit.position = position
// this works ok
var emit = bangEmitter.copy() as! SKEmitterNode
emit.position = position
}
}
Because copy() is a method defined by NSObject and is meant to be overriden by subclasses to provide their own implementation. NSObject itself doesn't support it and will throw an exception if you call copy() on it.
Since it's meant for subclassing, there's no way to tell what the class of the object that will be returned. In Objective-C, it returns an id; in Swift, this becomes AnyObject. Since you, the programmer, know what kind of object you are copying from, you can use as! SomeClass to tell the compiler what kind of object the copy is.
This also speaks to the difference between ObjectiveC and Swift. Objective-C is dynamic. In Objective-C, every time you send a message, the run time will check if the object responds to the message. This happens at run time. In Swift, you call a method and this happens at compile time. The compiler must know the object's type in order to call the right function / method.
This explains why you get emit as an SKEmitterNode in the debugger - this is run time. The compiler doesn't know that at compile time.
Using the as! is an indicator that a check may fail.
Swift 1.2 separates the notions of guaranteed conversion and forced conversion into two distinct operators. Guaranteed conversion is still performed with the as operator, but forced conversion now uses the as! operator. The ! is meant to indicate that the conversion may fail. This way, you know at a glance which conversions may cause the program to crash.
Reference: https://developer.apple.com/swift/blog/?id=23
Look up the definition of the function copy() and you'll see that it always returns Any, therefore you always need to cast it to the object that you're seeking.

argument for generic parameter could not be inferred

I'm trying to save an array with NSUserDefaults and then load the array, but I get the error "argument for generic parameter could not be inferred." Is there anything I am doing wrong? No one seems to be having this problem in swift, so I can't find any solutions.
IBAction func loadData(sender: AnyObject) {
if let testCompositeArray = defaults.objectForKey("testScoreSATArray") as? Array {
self.showDataLabel.text = defaults.objectForKey("testScoreSATArray") as Array
}
}
The reason you received your original error is that in Swift, Array is a generic container that holds values of a specific type. So you can have an Array<Int> that holds integers, or an Array<String> that holds strings. But you can’t have just an Array. The type of the thing the array contains is the generic parameter, and Swift is complaining because it can’t figure out what that type should be. Sometimes it can infer that type from the context of the code around it, but not always, as in this case.
You can resolve the problem by giving the type of the thing you are storing:
IBAction func loadData(sender: AnyObject) {
if let testCompositeArray = defaults.objectForKey("testScoreSATArray") as? Array<Int> {
self.showDataLabel.text = toString(testCompositeArray)
}
}
Instead of writing Array<Int>, you can write the shorter form, [Int]
You can also solve the problem by using NSArray, as you’ve found. Unlike Array, NSArray doesn’t use generics, since it originates in Objective-C which has a different approach to Swift. Instead, NSArray holds only one kind of thing, an AnyObject. This is is a reference that can point to instances of any class.
However, there’s a big downside to using NSArray and AnyObject, which is that every time you use a value they contain, you often have to “cast” the value to a real thing, like an integer or a string. This can be a pain, and worse, sometimes can cause errors when you assume you have one kind of thing when actually you have another. Swift generally encourages you to be more specific about types to avoid errors like this.

When constructing a Swift UnsafeMutablePointer manually, is destroy/dealloc obligatory after alloc?

Let's say that in Swift I construct a C array manually and pass it, like this:
override func drawRect(rect: CGRect) {
let c = UIGraphicsGetCurrentContext()
var arr = UnsafeMutablePointer<CGPoint>.alloc(4)
arr[0] = CGPoint(x:0,y:0)
arr[1] = CGPoint(x:50,y:50)
arr[2] = CGPoint(x:50,y:50)
arr[3] = CGPoint(x:0,y:100)
CGContextStrokeLineSegments(c, arr, 4)
}
(I know I don't have to do that, but just bear with me.) If I don't call destroy and/or dealloc on this UnsafeMutablePointer, am I leaking the memory for four CGPoints?
The documentation for UnsafeMutablePointer is pretty clear:
/// This type provides no automated
/// memory management, and therefore the user must take care to allocate
/// and free memory appropriately.
So if you allocate but don’t deallocate, you will leak memory. There’s no auto-deallocation on destruction of the pointer object.
Re whether you should destroy before deallocating, it’s also pretty clear:
/// The pointer can be in one of the following states:
///
/// - memory is not allocated (for example, pointer is null, or memory has
/// been deallocated previously);
///
/// - memory is allocated, but value has not been initialized;
///
/// - memory is allocated and value is initialized.
But bear in mind you can transition back and forth between these states. So after allocating then initializing then de-initialzing (aka destroying) the objects, the memory is no longer in the “initialized” state, so you can either re-initialize or deallocate it. You can also allocate, then deallocate, without ever initializing.
And when calling dealloc:
/// Deallocate `num` objects.
...
/// Precondition: the memory is not initialized.
///
/// Postcondition: the memory has been deallocated.
Therefore you must call destroy on any initialized objects before calling dealloc. You are probably right in that since something like CGPoint is totally inert (just a struct of two floating point nums) it probably doesn’t do any harm not to call destroy before you call dealloc but you can’t be certain without knowing the implementation (of both the pointer struct and the compiler probably, since the standard lib is a quasi-part of the language there could be some baked-in optimizations), and generally, it’s just not a good habit to get into. Sooner or later you’ll forget to destroy a String, and then you’ll be sorry.
(none of this accounts for the move operations btw which combine initializing new memory with destroying old memory)
If you were hoping for some kind of automated self-cleanup of memory by UnsafePointer, I don’t think this would be possible as a) it’s a struct, so can’t implement a deinit to auto-deallocate when going out of scope, and b) it doesn’t track it’s own size – you have to track how much you allocate, and supply that back explicitly in the call to deallocate.
There is something in the standard library that does auto-deallocate memory without you having to do it yourself – HeapBufferStorage, the one and only class in the standard library. Presumably it’s a class specifically to benefit from an implementation of deinit. There’s also HeapBuffer to manage it with, and this has a handy isUniquelyReferenced() function that allows you to tell if it’s been copied (even though it’s a struct) and so would allow you to implement copy-on-write capability similar to arrays and strings.
In Swift 2 UnsafeMutablePointer can be made a bit less frustrating by pairing alloc/dealloc with the new defer keyword:
let ptr = UnsafeMutablePointer<T>.alloc(1)
defer { ptr.dealloc(1) }
This is for others like me who found this question/answer thread by searching CGContextStrokeLineSegments. If your purpose is to call this function in Swift, you don't have to construct a C array pointer even though the function's second parameter is an UnsafeMutablePointer. You can directly pass a Swift array into it, even a non-mutable one, instead of a C pointer with its allocation and deallocation. For example:
override func drawRect(rect: CGRect) {
if let c = UIGraphicsGetCurrentContext()
{
let arr = [CGPoint(x:0,y:0), CGPoint(x:50,y:50), CGPoint(x:50,y:50), CGPoint(x:0,y:100)]
CGContextStrokeLineSegments(c, arr, 4)
}
}

If a function returns an UnsafeMutablePointer is it our responsibility to destroy and dealloc?

For example if I were to write this code:
var t = time_t()
time(&t)
let x = localtime(&t) // returns UnsafeMutablePointer<tm>
println("\(x.memory.tm_hour): \(x.memory.tm_min): \(x.memory.tm_sec)")
...would it also be necessary to also do the following?
x.destroy()
x.dealloc(1)
Or did we not allocate the memory and so therefore don't need to dismiss it?
Update #1:
If we imagine a function that returns an UnsafeMutablePointer:
func point() -> UnsafeMutablePointer<String> {
let a = UnsafeMutablePointer<String>.alloc(1)
a.initialize("Hello, world!")
return a
}
Calling this function would result in a pointer to an object that will never be destroyed unless we do the dirty work ourselves.
The question I'm asking here: Is a pointer received from a localtime() call any different?
The simulator and the playground both enable us to send one dealloc(1) call to the returned pointer, but should we be doing this or is the deallocation going to happen for a returned pointer by some other method at a later point?
At the moment I'm erring towards the assumption that we do need to destroy and dealloc.
Update #1.1:
The last assumption was wrong. I don't need to release, because I didn't create object.
Update #2:
I received some answers to the same query on the Apple dev forums.
In general, the answer to your question is yes. If you receive a pointer to memory which you would be responsible for freeing in C, then you are still responsible for freeing it when calling from swift ... [But] in this particular case you need do nothing. (JQ)
the routine itself maintains static memory for the result and you do not need to free them. (it would probably be a "bad thing" if you did) ... In general, you cannot know if you need to free up something pointed to by an UnsafePointer.... it depends on where that pointer obtains its value. (ST)
UnsafePointer's dealloc() is not compatible with free(). Pair alloc() with dealloc() and malloc and co. with free(). As pointed out previously, the function you're calling should tell you whether it's your response to free the result ... destroy() is only necessary if you have non-trivial content* in the memory referred to by the pointer, such as a strong reference or a Swift struct or enum. In general, if it came from C, you probably don't need to destroy() it. (In fact, you probably shouldn't destroy() it, because it wasn't initialized by Swift.) ... * "non-trivial content" is not an official Swift term. I'm using it by analogy with the C++ notion of "trivially copyable" (though not necessarily "trivial"). (STE)
Final Update:
I've now written a blogpost outlining my findings and assumptions with regard to the release of unsafe pointers taking onboard info from StackOverflow, Apple Dev Forums, Twitter and Apple's old documentation on allocating memory and releasing it, pre-ARC. See here.
From Swift library UnsafeMutablePointer<T>
A pointer to an object of type T. This type provides no automated
memory management, and therefore the user must take care to allocate
and free memory appropriately.
The pointer can be in one of the following states:
memory is not allocated (for example, pointer is null, or memory has
been deallocated previously);
memory is allocated, but value has not been initialized;
memory is allocated and value is initialized.
struct UnsafeMutablePointer<T> : RandomAccessIndexType, Hashable, NilLiteralConvertible { /**/}