What is CFArray and difference between CFArray vs NSArray - objective-c

this might be a duplicate question but i have go through the so many blogs and documents , but still i can't figure out what is CFArray.
As performance wise which one is best and when to use and which situation.
Please throw a light in this topic.

A CFArray is an NSArray and vice-versa.
Core Foundation (where the CF comes from in the name) is Apple's C-oriented collection of functions and data types. Cocoa (the NS comes from NextStep, Cocoa's ancestor) is Apple's Objective-C framework.
Certain types in the two two frameworks are toll-free bridged - that means the data structure is shared between the two frameworks, Core Foundation operates on it using C-style function calls, Cocoa operates on it using Objective-C style method calls.
Sometimes one framework might provide operations the other does not, but in general you use Cocoa from Objective-C and Core Foundation from C when considering a toll-free bridge type.
Cocoa objects are automatically managed by ARC, a big advantage. In Core Foundation you use manual memory management. Objective-C has a number of "bridge" casts which inform the compiler when you are transferring responsibility for memory management between ARC and manual Core Foundation calls.
Given they are the same data-structure any performance difference is down to the such things as an extra call-level overhead if a Cocoa method just calls a Core Foundation one, etc. In general you should not be concerned about this unless you've identified a performance issue.
HTH

CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, arraySize, &kCFTypeArrayCallBacks);
for (int i=0;i<arraySize;i++) {
CFStringRef string = CFBridgingRetain(#"This is an awesome string"); // CFStringCreateWithCString(kCFAllocatorDefault, "This is an awesome string", kCFStringEncodingUTF8);
CFArrayAppendValue(array, string);
CFRelease(string);
}
CFIndex count = CFArrayGetCount(array);
for (int i=0;i<count;i++) {
CFStringRef string = CFArrayGetValueAtIndex(array, i);
}
CFRelease(array);
let’s go over the CFArray code. In the CoreFoundation version, we first create a mutable CFArray (CFMutableArray) via the CFArrayCreateMutable() function call, providing the allocator, array size and the callback function. We then setup a very conventional-looking for loop, iterating over the array the number of time indicated by arraySize (this number will change in our tests). A string is then created and appended to the array and released. You might notice that we actually create and Objective-C string literal and transfer the ownership over to CoreFoundation via CFBridgingRetain(). This means that ARC will no longer take care of releasing the string for us and we must do so explicitly with CFRelease(). An alternative to this is to use create a string with a CoreFoundation call to CFStringCreateWithCString() (which is commented out), but this method is much slower and we are interested in comparing the array performance, not string allocation performance. The second portion of the code will get the array count, setup another loop and get the value at index with every iteration. We don’t actually do anything with the string.
NSMutableArray *container = [[NSMutableArray alloc] initWithCapacity:arraySize];
for (int i=0;i<arraySize;i++) {
NSString *string = #"This is an awesome string";
[container addObject:string];
}
NSUInteger count = [container count];
for (int i=0;i<count;i++) { // (NSString *string in container) {
NSString *string = container[i];
}
The Objective-C Foundation counterpart is very similar in nature but removes the need for CFRelease() as we are under ARC. Most of this code is pretty self-explanatory so we won’t go through it in detail. One thing to point out, however, is that with Foundation you have the option of using Fast Enumeration, which will actually give you some performance gains, as we’ll see later on. This is commented out beside the conventional for loop.

It's important to note, that while the other answers are correct in the common case, it is possible to create CFArray variants that are completely incompatible with Objective C. When a CFArray is created, callback functions are provided. If the standard kCFTypeArrayCallBacks is provided, the array is indeed compatible and toll-free bridged to Objective C. However, it is possible to provide custom callback functions, and, for example, include value types as the array values (whereas NSArray requires that all values are CFType/objc_object).
It is important to know this difference, as in some rare cases, the Apple frameworks return CFArray objects which must not be bridged to NSArray, especially when using ARC.

Related

Objc Cocoa MRC - Released and autoreleased objectsI have to write him up to see application

I'm writing a C++ application using Metal API (objective C) and MRC (Manual Reference Counting). I have a very limited experience with ObjC. Most of the Metal API objects are defined as protocols and created as an object returned from C-function or other object's method (ex. MTLDevice newBufferWithLength). To know how to release objects created this way I need to know if they have been set autoreleased or not (I can't call release an autoreleased object with retain count 1 for instance). The problem is I can't find any description in Metal API documentation which would answer this question. I've only read in user guide that all so called lightweight objects are created autoreleased. There are three examples of autoreleased objects but not sure if I can just assume that rest of the objects are not autoreleased. In cocoa many objects also may be created without alloc+init, being returned from a static method (ex NSString string) so the problem seems not to be only Metal related.
Thank you for your help.
The usual Objective-C rule is that creating scope is also responsible to release object. So, in virtually all cases, except well-documented exceptions, returned object is autoreleased (both returned through return value or out-arguments). More correct way to see it is that object is always returned with +0 scope-local retain count, so you are expected to retain it if needed. Reading the manual it seems that Metal API is one of Apple's frameworks, so it should follow this rule unless warned with bold statements. C functions in Objective-C are also expected to behave that way. (There is no difference between a method and a function in terms of resource management.)
For that "alloc-init vs. [NSString string]" part: MRC code either returns [NSString string], which is already +0, or [[[NSString alloc] init] autorelease]. Otherwise it breaks the convention. Exceptions are -[init] and +[new...] methods itself that return +1. Under ARC there is no difference between alloc-init/string, because ARC knows the convention and does the right thing, optimizing excessive retains/releases where possible.
Also note that -[retainCount] is meaningless and "considered harmful", because you never know how many retain-autorelease calls were performed and what objc-runtime accounting is in effect even with your own objects.
ARC is really a great option unless you're writing some sort of Objective-C -to- Whatever bridge, where retain counts and/or cycles must be managed explicitly due to lack of context. It doesn't take anything from you, giving in most cases a big advantage of not managing resources at all.

If you bridge a CFArrayRef of CFStringRefs to NSArray, can you treat the contents as NSStrings?

Suppose I have a CFArrayRef containing CFStringRefs inside it and I bridge it over to NSArray using CFBridgingRelease(). Can I now treat the contents of the array as regular NSString instances and call all of the usual NSString methods?
If so, does this mean toll-free bridging happens recursively throughout the object when it's bridged? E.g. if I had a CFArray of CFArrays of CFDictionaries or something, they'd all be transparently converted to NSArray, NSDictionary, etc?
Toll free bridging does not involve any conversion (or there would be a cost), so talking about doing it recursively does not make sense.
What toll free bridging does in your case is determine who is responsible for managing the lifetime of the object - the programmer for the CF array, ARC for the NS array.
Further whether an object internally uses manual memory management or ARC is not important to the user of that object - they can use either style.
Combine the above and you have your answer: once you've handed your CF array of strings over to ARC your job is done.
HTH
CRD's answer is good and I've given it a +1. Here's a bit more explanation:
First, type-casting is a purely compile-time thing. And it doesn't cost anything. It just tells the compiler not to complain.
Toll-free casting of Core Foundation types to Cocoa types is because those objects are, under the hood, the same thing. The cast is just necessary to inform the compiler of that fact. Such a cast doesn't "do" anything. For example, in non-ARC code:
CFStringRef cfstring = /* ... */;
NSString* nsstring = (NSString*)cfstring;
That assignment is still just an assignment. The pointer value from cfstring is still just copied verbatim into the storage of nsstring. Nothing else happens.
Depending on how you obtained the CFString that cfstring was pointing to, you may have had a responsibility to release it. Since this is non-ARC, you still have that responsibility after it has been assigned to nsstring, which you can discharge either by calling CFRelease(cfstring) or [nsstring release] or [nsstring autorelease] when you're done with it. Once you do that, the value in both variables must be considered unusable as dangling pointers.
The case with ARC is only slightly different. An ARC bridging cast is also a compile-time thing, but it affects what code the compiler emits for automatic memory management. Since it has emitted different code, that technically has implications for run-time, but they are not related to the type-cast as such. The bridging cast tells the compiler whether it should emit retains or releases (or neither) of the object which is the subject of the expression. That's all; just a question of retaining or releasing the object. So, it has no effect on, say, objects within an array because those objects are not the subject of the expression, the array is. And it doesn't even do anything to the array beyond potentially retaining or releasing it.
Let me try and take a simpler approach to an answer:
A CFArrayRef can be treated as an NSArray* and vice versa.
A CFStringRef can be treated as an NSString* and vice versa.
Thus, an CFArray of CFStrings is an NSArray of NSStrings. You just need to cast it. (In so doing with __bridge_*, you also transfer the memory management to ARC.)

NSNumber vs. primitive int for NSArray

I am learning Objective-C/Cocoa using the 4th edition of Cocoa Programming for Mac OSX. I apologize for the basic question but I'm one of those people that really need to understand the insides of everything in order for it to make sense to me and this book doesn't always do that to my needs. I've already picked up the basics of C++ and now I'm learning Obj-C so that is my background. This is a snippet of code that I'm learning...
for (i= 0; i < 10; i++) {
NSNumber *newNumber = [[NSNumber alloc] initWithInt:(i * 3)];
[array addObject:newNumber];
}
My question is why would you create instances of NSNumber to add to the array instead of just a single integer variable. It seems like it is just extra overhead creating a new instance each loop that could be avoided. But I'm sure the authors know what they are doing and there is a reason for it, could someone please explain?
NSArray can only hold objects, not primitive types. NSNumber and NSValue are used to wrap primitive types in objects, so they can be stored in foundation collections like NSArray, NSDictionary, and NSSet (and their mutable / ordered counterparts). As Peter Hosey points out in the comments:
The common term for this is "boxing" (as in boxing them up), and the inverse — extracting the primitive value from a box object — is unboxing.
Because Core Foundation classes are not able to work directly with primitive types, they can deal only with NSObject instances (which are objects in OOP terms, not primitives)
That's why you are forced to wrap your int variable with a NSNumber (or NSData or NSValue). This certainly brings some overhead, indeed if you need performance critical code, I suggest you to use Objective-C++ and rely on STL (eg std::vector<int>).
I personally had to discard all core foundation classes in favour of STL for big parts of a game engine just because they couldn't keep it up when managing large amounts of primitive data.
NSArray deals directly with pointers – and by extension, objects – whereas int is a primitive type. NSNumber exists to bridge this gap. An NSNumber can be cast from an int, float, or even a bool. The salient point is that it provides an object with a pointer, and that pointer can be added to the array.

Pointers, am I using them correctly? Objective-c/cocoa

I have this in my #interface
struct track currentTrack;
struct track previousTrack;
int anInt;
Since these are not objects, I do not have to have them like int* anInt right?
And if setting non-object values like ints, boolean, etc, I do not have to release the old value right (assuming non-GC environment)?
The struct contains objects:
typedef struct track {
NSString* theId;
NSString* title;
} *track;
Am I doing that correctly?
Lastly, I access the struct like this:
[currentTrack.title ...];
currentTrack.theId = #"asdf"; //LINE 1
I'm also manually managing the memory (from a setter) for the struct like this:
[currentTrack.title autorelease];
currentTrack.title = [newTitle retain];
If I'm understanding the garbage collection correctly, I should be able to ditch that and just set it like LINE 1 (above)?
Also with garbage collection, I don't need a dealloc method right?
If I use garbage collection does this mean it only runs on OS 10.5+? And any other thing I should know before I switch to garbage collected code?
Sorry there are so many questions. Very new to objective-c and desktop programming.
Thanks
I have this in my #interface
struct track currentTrack;
struct track previousTrack;
int anInt;
Since these are not objects, I do not have to have them like int* anInt right?
That would declare a pointer to an int stored somewhere else.
And if setting non-object values like ints, boolean, etc, I do not have to release the old value right (assuming non-GC environment)?
release is a message. You can only send a message to a Cocoa (or, in some cases, Core Foundation) object.
The struct contains objects:
typedef struct track {
NSString* theId;
NSString* title;
More precisely, it contains pointers to objects.
You can't ever have an object stored directly in a variable; you can only allocate it dynamically by sending an alloc message to a class, and receive the pointer to the allocated instance. Similarly, you can only send a message to a pointer to an object; you cannot and should not dereference a pointer to an object.
For these reasons, we almost always elide the “a pointer to”. We speak of the pointers as if they are the objects, but, in precise truth, they are not.
} *track;
That's correct if you want to declare the track type as being a pointer to a struct track. Generally, this will confuse people.
Lastly, I access the struct like this:
[currentTrack.title ...];
currentTrack.theId = #"asdf"; //LINE 1
So the previous line is line 0? ;)
I'm also manually managing the memory (from a setter) for the struct like this:
[currentTrack.title autorelease];
currentTrack.title = [newTitle retain];
If I'm understanding the garbage collection correctly, I should be able to ditch that and just set it like LINE 1 (above)?
If you're using garbage collection, then the autorelease and retain messages will do nothing, so yes, the plain assignment and the assignment with (ineffectual) release and retain messages are equivalent.
I do question why you're putting this information in a structure and not a model object, though.
Also with garbage collection, I don't need a dealloc method right? If I use garbage collection does this mean it only runs on OS 10.5+? And any other thing I should know before I switch to garbage collected code?
Yes: Read the Garbage Collection Programming Guide. It tells you everything you need to know, including the answers to the previous two questions.
As for pointers, you may want to read my pointers tutorial. The title says C, but everything in C is also true in Objective-C.
Although you seem to understand this stuff all right in general, I'd strongly recommand against storing objects in a struct. Getting proper memory management for that will be very troublesome — because even though the struct itself doesn't require memory management, the objects still do, and unless the struct is only ever accessed through a function API (essentially making it s poor man's object), you're going to have a tough time ensuring that happens. Like Peter said, that makes sense to be a model object.
Correct, correct, no, yes, correct, yes, and Apple's Garbage Collection Programming Guide is a good read.

What is the purpose of having both NSMutableString and NSString?

Why does Objective C provide both class NSString and subclass NSMutableString rather than just provide NSMutableString? Isn't a NSString equivalent to "const NSMutableString"?
In C++, you have only one string class, std::string, and if you want a constant you declare a const std:string.
I'm interested in knowing why I shouldn't just use NSMutableString everywhere and never bother with NSString? There must be a reason, or the language designers wouldn't provide both. maybe it takes up less storage or something?
It is very possible, and even likely, that there are optimizations in place that are only allowed when strings are immutable.
In fact running
NSString *A = #"Bob";
NSString *B = #"Bob";
in the debugger immediately shows that they are both pointers to the same string. In fact
NSString *C = [NSString stringWithString:#"Bob"];
NSString *D = [A copy];
both point to the same memory address as well. Meanwhile
NSString *E = [NSMutableString stringWithString:#"Bob"];
points to a different string.
So yes, using NSStrings are more efficient in some cases. And in general cocoa lends itself to returning a new copy of a string rather than an edited one. However, I can't really argue that you shouldn't use a mutable string everywhere, but it does seem to go against the general guidelines for the framework.
In my own work I tend to only use mutable variants where I need to edit things directly. It's just a little backwards from the C/C++ style of everything mutable unless you need a const, everything is const unless you need mutability.
The reason for both classes is the same reason that you sometimes use a std::string and sometimes use a const std::string. However, unlike C++, Objective-C doesn't have const methods, so they instead separate const- from non-const- methods into two different classes. This is also seen in many of the core classes, such as NSArray (NSMutableArray), NSDictionary (NSMutableDictionary), etc.
I would say the general rule is "don't use a class whose purpose is to provide functionality you don't need". If you need to change the contents of a string directly, use NSMutableString. If not, use NSString. In terms of size and how much heap space they take up, the classes themselves should be pretty similar.
I think the usage of an immutable string is a hint for the compiler which can perform optimizations by knowning it won't change.