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.
Related
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.
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.)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
what is the point of pointers in objective language
I am confused as to when and why pointers are used in Obj-C code. I am new to Obj-C and have a good grounding in C++ from an intro course at my university.
NSDate *now = [NSDate date];
Why is a pointer used here (and what exactly is its purpose?), and not here...
NSUInteger arrayLength = [<some array> count];
I am much more comfortable with the second example, but the first is still puzzles me.
It's the wording of the typedefs of Apple which are confusing.
NSUInteger
is just a fancy typedef for unsigned int; therefore it's a scalar type and not an object; you don't need a pointer to it in general for such a simple use case.
However,
NSDate
is a Foundation class; it means that its instances are proper Objective-C objects. As you probably know, Objective-C is a fully dynamic language: no static instances of classes are permitted, so every object is essentially a pointer (well, rather the allocated memory behind the pointer). So when you work with Objective-C objects, you always need a pointer to them.
Well, there are a few fundamental differences between Objective-C and C++. In Objective-C, there is actually a "generic object" (type "id"), and you can pass objects around without worrying about classes.
One of the implementation details that makes this possible is that Objective-C doesn't have "static" objects; all objects are created through the equivalent of "new" and are accessed through a pointer (string literals might be different, but they are still of type "NSString*"). It's just the way it is in Objective-C; you simply cannot have an "NSString MyString".
Because of this, the whole "objects are just objects and the compiler doesn't actually what you're dealing with" is possible because all objects are just simple pointers -- they are all the same size. The compiler can pass them around without knowing what they are, you can store them in containers without the containers knowing what they are etc.
Objective-C and C++ may both be "object-oriented" extensions of C, but they are quite different nonetheless.
EDIT: you can write stuff like "NSString* MyString" so the compiler knows what kind of object it is dealing with, but that's just convenience: you can still put other objects into that pointer (and, in fact, since the "new" equivalent usually returns id, one of the more common mistakes that I make is to "new" a different class from what the pointer says)
On the positive side, the compiler will warn you if you assign e.g. an NSWindow* to MyString, and it will also warn you if you call "open" on MyString. However, this is just an added benefit from the compiler; you could just as well declare everything as "id", or cast away the warnings.
With all the useful things you get from NSArray and NSMutableArray, why would you ever use a "C Style" array with Objective-C objects?
NSString *array[] = {#"dog", #"cat", #"boy"};
For short, fixed arrays, the availability of a nice compact initialization syntax (as you've demonstrated) can be nice. In certain cases, a C style array may also offer a performance benefit compared to using NSArray. Another thing that comes to mind is that NSArray doesn't offer any built in support for multidimensional arrays, while multidimensional C arrays are easy.
And of course, there's the fact that you can only store objects in NSArray, not C-primitive types, but you asked specifically about using C arrays with Objective-C objects.
All useful things come at a price.
Ever try making an NSArray of ints? You can't. You MUST use NSNumber.
Why? Because NSArray doesn't know what to do with things it doesn't know how to memory-manage... and the only things that conform to it's memory-management requirements are things based on NSObject.
It's just one example, but there are plenty of others.
Bottom line is, there is rarely ever one single "best" answer to anything. NSArray is no exception.
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.