Hi. Can someone briefly explain how to pick one vs the other? Also, can anyone clarify some of the ARC terminology, such as balanced vs unbalanced retain?
As an example of what I am doing - I am creating a mutable byte buffer which is passed to a C library as a pointer for further processing.
It’s hard to respond here without more info about the specific issue you’re wrangling. Consider this:
I am creating a mutable byte buffer which is passed to a C
library as a pointer for further processing.
The safest option here is to use one of the withXxx(…) methods. For example:
let d = Data("Hello Cruel World!".utf8)
d.withUnsafeBytes { buf in
someCFunction(buf.baseAddress!, buf.count)
}
Note This example uses Data but the same technique works for [UInt8].
These withXxx(…) methods manage the lifetime of the unsafe pointer. As long as you don’t access the pointer after the closure has returned, you’re golden.
Where things get tricky is when you need to pass a buffer to C and have C maintain ongoing access to it. In that case the withXxx(…) methods aren’t appropriate and you have to start managing memory manually.
If that’s the case, please post more details about what you’re doing and we can explore your options.
To be honest, it is the latter case. I am passing a buffer around for reading/writing in a callback oriented system (libuv).
Well, I have a potential solution in mind that does not involve manual memory management.
(Create a container class with a buffer and a key on every new connection. Store this class in a 'global' array and pass a pointer to this object around. Once the 'close' callback is finished, remove the container class by key from the array.)
However, I am still curious at how a manual memory management should be done in this case. It might result in a more efficient code too if done well.
Furthermore, I am just wondering why would one prefer one type over the other. For example, UnsafeMutableRawPointer vs Data? Or Data vs Unmanaged? And lastly, passRetained vs passUnretained?
UnsafeMutableRawPointer is roughly equivalent to a C buffer pointer and length. It’s pretty much completely unsafe [1].
Data is a value type that uses CoW under the covers.
Or Data vs Unmanaged?
Unmanaged is a mechanism to work with reference counts directly. Most Swift code uses automatic reference counting (ARC), which means the compiler takes care of the reference counts for you. Unmanaged is useful in situations where you’re escaping the ARC world in order to interoperate with manual retain/release environments, like a C library.
You use passRetained(…) when you need to pass an unmanaged value to C (for example) and you want to increment the retain count on that value. This is useful for escaping contexts, with the obvious caveat that you have to decrement the retain count at some point.
You use passUnretained(…) when you need to pass an unmanaged value to C and don’t want to retain that value. This is useful for non-escaping contexts.
There are similar takeRetainedValue() and takeUnretainedValue() routines for when C is passing you an unmanaged value and you want to bring it back into the ARC world.