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.
Related
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.
I want to ask a question about the objective C. When I study the library from the apple developer website. I always see that there are some subclass called "mutable". For example, the NSArray and NSMutableArray. What does it mean about this word. Are there some special meaning? Can anyone tell me? Thank you.
It means you can change its values. If you look at the NSMutableArray docs, you'll see it defines extra methods like -addObject:. NSArray by itself doesn't have these (and can thus be more efficient / take less memory in implementation).
Also note, if you call [myMutableArray copy] you'll get a non-mutable copy of it (which you must later release0. And similarly there's -mutableCopy.
Mutable means you can change it. Look at the difference between addObject in NSMutableArray and arrayByAddingObject in NSArray.
From the Objective-C Beginner's Guide it states the answer to your specific question:
There are two kinds of arrays (and of
usually most data oriented Foundation
classes) NSArray and NSMutableArray.
As the name suggests, Mutable is
changable, NSArray then is not. This
means you can make an NSArray but once
you have you can't change the length.
This tech note also implies you can change the length of a mutable array after the array has been created.
In general mutability stems from these meanings. This will help provide a more broad understanding for when you encounter it elsewhere.
I am not sure if many of you are familiar with the box2d physics engine, but I am using it within cocos2d and objective c.
This more or less could be a general objective-c question though, I am performing this:
NSMutableArray *allShapes = [[NSMutableArray array] retain];
b2PolygonShape shape;
..
..
[allShapes addObject:shape];
and receiving this error on the addObject definition on build:
cannot convert 'b2PolygonShape' to 'objc_object*' in argument passing
So more or less I guess I want to know how to add a b2PolygonShape to a mutable array. b2PolygonShape appears to just be a class, not a struct or anything like that. The closest thing I could find on google to which I think could do this is described as 'encapsulating the b2PolygonShape as an NSObject and then add that to the array', but not sure the best way to do this, however I would have thought this object should add using addObject, as some of my other instantiated class objects add to arrays fine.
Is this all because b2PolygonShape does not inherit NSObject at it's root?
Thanks
b2PolygonShape is a C++ class, not an ObjC class. You can only put ObjC instances into "NS-containers".
Since you need C++ anyway, it's better to use a std::vector<b2PolygonShape>.
NS-container classes can (as KennyTM pointed out) only store NSObjects. This can be a bit of a pain sometimes. But there are plenty of alternatives to NS-containers.
You can write Objective-C wrapper classes (or use NSValue), and store these in an NSArray.
You could use a plain old C array (though, that may not serve your needs, if the array size is undefined and shrinks and grows)
You could use a hash table to store your references.
A linked list of structs can also come in handy, and is fairly easy to create and maintain.
Should you decide to stick to std::vector, which is as good a solution as any, you can read more about that at: http://www.cplusplus.com/reference/stl/vector/
I have an integer array in my Objective-C program. I'd like to sort it (ascending or descending, doesn't matter). In C++ I'd use the sort algorithm in the STL Algorithm library. How can I do this?
The "Cocoa" way is to create NSNumber objects, add them to an NSArray, and use the sortUsingSelector:#selector(compare:) method (or one of the other NSArray sort methods).
If you want to create a C array of primitive NSInteger (int) values, you can use the built-in qsort(…) function of C.
Even though this question has already been answered, I would like to add that you can also use STL collections with Objective-C++ and iPhone programming. Here is a link to a previous discussion on the topic.
I am fairly new to Objective-C and was wondering what the best way to manage collections of tuples was. In C I would use a 2D array or a struct.
Should I be creating objects to contain these tuples? It seems like overkill for just sorting lists or is there no real extra load generated by object initialisation?
There definitely is some overhead in the generation of objects. For a small number of objects, then using ObjC data structures is still appropriate. If you have a large number of tuples, I would manage them in a C array of structs. Remember, Objective-C is really just C. It is appropriate and common to use C constructs in Objective-C (to a point; learning where that point is represents a major milestone in becoming a good Objective-C developer).
Typically for this kind of data structure, I would probably create a single Objective-C object that managed the entire collection. So external callers would see an Objective-C interface, but the internal data would be stored in a more efficient C structure.
If it is common to access a lot of tuples quickly, my collection object would probably provide "get" methods similar to [NSArray getObjects:range:]. ObjC methods that begin with "get" indicate that the first parameter is a pointer that will be overwritten by the method. This is commonly used for high-performance C-like access to things managed by an ObjC object.
This kind of data structure is exactly the way ObjC developers merge the elegance and maintainability of ObjC with the performance and simplicity of C.
I think you'll have to settle for an NSArray of NSArray objects, or maybe an NSArray of NSDictionary objects. You can always roll your own class, or do it the way you would do in C.
There are a couple different ways you could go about this:
CoreData. While it's not technically a database, it can behave a lot like one. If you don't need persistence between app runs, then consider using the NSInMemoryStoreType store type, as opposed to an NSSQLiteStoreType or other option. However, if you're going to want to join tuples together, using CoreData will absolutely not work (this, IMO, is the main reason why CoreData is not a database).
Use a real database. SQLite ships on every Mac and iPhone and is pretty easy to use if you use wrappers like FMDB or SQLite Persistent Objects or PLDatabase or EGODatabase or the GTMSQLite wrapper by Google.
A tuple is really just a collection of key-value pairs, so you could just use an NSMutableArray of NSMutableDictionaries. You obviously won't get to use SQL syntax, and any joins/queries you have to run yourself, but this would definitely have the easiest setup.
Write a tuple class and store those in an NSMutableArray (similar to #3, just enforcing a common set of attributes on your tuples).