UnsafeMutablePointer<UInt8>: What's the risk? - swift

I'm receiving one of these in a callback from an Objective-C library: UnsafeMutablePointer<UInt8>
I'm able to parse it. I'm also able to create one to send it back to the library, but: What are the risks of working with the "unsafe" type? How do I avoid those risks?
Also, the Objective-C library is using uint8_t * which bridges to Swift as this UnsafeMutablePointer<UInt8>... is this the best thing for Swift interop?

UnsafeMutablePointer is how you represent a C pointer in Swift. It's unsafe because the underlying memory the pointer points to could change at anytime without the Swift pointer knowing. It also has no information about the size of the memory block that it points to (thanks Martin).
If your library requires you to use C types, in this case a pointer to a uint8_t, then you must use UnsafeMutablePointer. Otherwise I if you just want to represent an array of numbers I would wrap all of the uint8_t types in an NSArray as NSNumber types (or NSData if you are pointing to a byte stream) for easier bridging.
You can avoid these risks by dereferencing the pointer (if it is non-nil) and copying the value stored at the pointer to a variable in your Swift application.

Related

Conversion between object and non-toll-free bridged types

As we know it is very easy to make conversion between toll-free bridged types and objective-c types such as CFArrayRef and NSArray. Yesterday, I found a piece of code that convert CGImageRef (which is not a tool-free bridged type) to id as below:
CALayer *imgLayer = [CALayer layer];
imgLayer.contents = (id)aImage.CGImage;
However, it works fine. But I don't understand it, because CGImageRef is not belong to toll-free bridged types according to apple's document. Look at the second line code, imgLayer should retain the value assigned to the property contents. Because CGImageRef is converted to id so I think in the property contents' setter method it will send a retain message to that object like this [xxx retain]. But aImage.CGImage is not an object so I don't think this retain message will perform correctly (however it will). So my question is what is the actual action behind this conversion?
These methods are an exception to the rule that Apple added for convenience. Since the compiler knows about Objective-C naming conventions and the implied memory management, Core Foundation objects returned by objective-C functions will be automatically converted and handled correctly.
See the section The Compiler Handles CF Objects Returned From Cocoa Methods in this document
Toll-free bridging is a bit of an outdated term. It referred to the seamless casting between Core Foundation C objects and Objective-C objects. However, with ARC the transition is no longer as seamless since the compiler needs hints about what to do with the corresponding objects after bridging them. In this case, though, it gets its hints from the naming conventions of the method.
Furthermore, all Core Foundation objects can essentially be cast to Objective-C objects. If there is no corresponding type then they will simply become a special catch-all class (NSCFType) that was designed for this purpose.

How to use the CFMutableArrray

I am reading a video file using AVFoundation framework and getting the image buffers as CMSampleBuferRef, I added the buffers in CFMutableArrayRef using CFArrayAppendValue() function.
But If I want to retrieve from that array, Is there any way?
Apple document for CFMutableArrayRef gives no method to retrive from array.
You're looking for the CFArray function CFArrayGetValueAtIndex, or something similar. CFMutableArray's "inherit" from CFArrays, and the documentation on CFMutableArray only contains the API that differs from CFArray.
See the docs here.
In addition to using the APIs Matt pointed out (+1), CFMutableArray is toll-free-bridged with NSMutableArray. you can simply cast an instance of a CFMutableArray to an NSMutableArray and use NSMutableArray's methods (or the other way around). Following the cast to NSMutableArray, you can use -[NSArray objectAtIndex:].
Many Foundation types have CoreFoundation counterparts which are toll free bridged. As a toll free bridged type, the cast does not introduce a promotion or conversion. Think of them as the same type, and that instances may be converted/cast to their CF-NS counterparts without introducing overhead or change to the instance. Technically, implicit reference counting may be introduced if your implementation uses NS-types rather than CF-types under ARC.
This may be useful if you are writing in ObjC, and are more familiar with the ObjC APIs.

does objective-c methods support "pass by value"?

Does objective-c methods support "pass by value"? Or perhaps to be more specific:
Is the default behavior for parameters passed into a method pass-by-reference?
If yes, are there any variations from this in some circumstances - for example if the parameter is just a basic int as opposed to an object? (or is this not relevant in objective-c)
Is there anyway to have a method support pass-by-value for a basic variable such as int?
Is there anyway to have a method support pass-by-value for an object? (I'm assuming no here, but for completeness will ask. Of course one could within the message do the copy yourself, however for this approach I'll consider this not to be something objective-c methods offers you, i.e. rather it was a do-it-yourself)
thanks
Objective-C does not support references, at least not in the C++ sense of the term.
All Objective-C objects are allocated on the heap, and therefore all "object variables" must in fact be pointer types. Whether a pointer can be considered to be effectively the equivalent of a reference is open to debate. When talking C++ for example, there are clear semantic differences (otherwise, what's the point...)
So to answer your questions:
No, Objective-C only supports pass-by-value. If you pass an object pointer to a method, you pass the pointer by value - you are not passing a reference.
There is no inherent difference between objects and primitives in this regard, apart from the fact that objects are always referred to by pointer, never by value. You can pass a primitive type pointer in if you like.
Yes. This is always the case. Again, if you pass in a pointer to a primitive, you are passing a pointer by value, not a reference.
You're pretty much bang on the mark with this one, other than the fact that you're passing around pointers, not references.
No. It's pass-by-value by default, like in C. Except for the fact that for the Objective C class instance references, the value is a reference. So Objective C class instances are passed effectively by reference.
N/A
See 1.
Not really. You can serialize, pass the string, and recreate inside. Or you can have the object store its ivars as a structure and pass that structure by value. Some objects support cloning.

Correct Memory Management for [string UTF8String]

I'm somewhat new to objective-c and I'm not sure what the correct memory management for this code is.
const unsigned char * data =(const unsigned char *) [string UTF8String];
When I call free on data I get an error. Do I need to clean up after this call?
No. "UTF8String" does not contain the words alloc, copy, retain, or create. Thus, you're not responsible for that memory.
Note that if you want that data to stick around after string is released, you should copy it; by the contract, you're not responsible for that memory, but you are also not guaranteed that it will last beyond the scope of the object that gave it to you.
You do not need to free it.
In Cocoa, if a method does not contain the words alloc, init, or copy, you do not own the object that is returned from said method.
-UTF8String actually points to the cstring representation of the NSString object you are calling it on. When the object's state changes, the UTF8String also changes.
As stated in the documentation, it is automatically freed the same way an autoreleased object would be.
technically speaking, free() is used to remove memory allocated using malloc() from the heap.
malloc() was not used to allocate the memory. remember that objective-c is c with extensions.
the data variable will remain in memory based on the c language 'scoping' rules.

Storing a C struct in CFMutableDictionary

Since there is no counterpart to NSValue in Core Foundation, how are we supposed to store C structs in a CFMutableDictionary?
First, you can put an NSvalue in a CFMutableDictionary as-is, so the answer is "use NSValue." But I assume the rest of your question is "without using any Cocoa objects." In that case, just create a non-retaining CFMutableDictionary, and you can put any pointer you want into it. See "Defining Custom Collection Callbacks" for some example code. I use these a lot.
Remember that these still have to be pointers, so you're going to have to allocate your structs on the heap, not the stack. And that means that memory management is now your problem. Of course you could create a custom set of callbacks that do whatever you want, so if you're using boost or something else with its own ref-counting system, you can still implement that with CFMutableDictionary.
And of course you can replace the struct with a small data object. That's usually a lot easier. But different problems need different solutions.
CFMutableDictionary
CFDictionaryAddValue
A CFType object or a pointer value to add to the dictionary.
you just pass a pointer to your struct.