I want to have a mutable array with primitives in obj-c (selectors). What's the recommended way to do this? NSArray and those can only hold objects.
You should use an NSValue to wrap the selector or any other primitive type you need. In Cocoa SEL is some kind of pointer, so you can use [NSValue valueWithPointer:whatever] to construct it and [value pointerValue] to get it out. Or, in general you can use [NSValue valueWithBytes:&whatever objCType:#encode(SEL)]; this works for any type.
If you want to store an array of SEL objects, the easiest thing would be to convert the SELs to NSStrings using the NSStringFromSelector() function, store them in an NSMutableArray, and then convert them back to SELs when you pull them out using NSSelectorFromString() function.
Other than managing a C-style array yourself (which is definitely not the best option, IMO), your only option is to use NSArray/NSMutableArray, and store the numbers using NSNumber. It's slightly more annoying to get the value out than with the actual numeric type, but it does free you from managing the array's memory yourself.
Since the primitive types are generally just numbers (be they integer or floating-point) or pointers, what's the problem with using the classes used to wrap those up for your purposes? An NSMutableArray of NSNumbers, for example?
Related
Not sure why Objective-C decided to use NSNumber instead of float, double, etc. How is this type represented on disk?
NSNumber is toll-free bridged with CFNumber. In recent implementations of Core Foundation, CFNumber is a tagged pointer. This lets it be treated as an object, but without all the overhead of an object. Instead, the value is encoded in the object pointer (and isn't actually a pointer).
See Tagged pointers and fast-pathed CFNumber integers in Lion.
NSNumber is a descendant of NSObject, so it can go wherever an id can go: NSarray, NSDictionary, and so on. Primitives such as int and double cannot go in these classes, because they do not inherit from NSObject, and hence cannot participate in collections etc.
If I were to guess on the internals of NSNumber. I'd say it's a union and a type selector field. However, the beauty of encapsulation lets me successfully program to NSNumber without knowing a first thing about its representation (and not missing that knowledge).
One thing to keep in mind is that Objective-C is a super-set of C, so they didn't decide to use NSNumber instead of the primitive types (float, double, etc.) but in addition to them. If you don't need the functionality of NSNumber, then just use the primitive types and save the overhead of creating/destroying the objects. Many functions in iOS (notably the array type functions) only work with objects (descendants of NSObject). Therefore, if you want to pass some type of number to one of these functions, you need an object representation of it. This is where NSNumber comes in.
To quote the documentation on NSNumber:
NSNumber is a subclass of NSValue that offers a value as any C scalar
(numeric) type. It defines a set of methods specifically for setting
and accessing the value as a signed or unsigned char, short int, int,
long int, long long int, float, or double or as a BOOL. (Note that
number objects do not necessarily preserve the type they are created
with.) It also defines a compare: method to determine the ordering of
two NSNumber objects.
Note that internally the actual value is stored either as an integer or as a floating point number (within either a tagged pointer as Jay describes or a union in an object), depending on what value you are storing. This is important to know as if you try to store a number like "32.1" it will store it as a floating point number and when you retrieve it you will most likely get something like "32.09999999999999".
As far as storing it to disk, if you need to do this then you typically store it with encodeWithCoder and retrieve it with initWithEncoder which converts it to a format intended to be saved to disk and later read back in.
I have an NSArray consisting of NSNumbers and I want to convert this to an NSArray of NSStrings, by getting the stringValue of each NSNumber in the first array.
The method that comes to my mind is iterating each value in the first one, getting its string value and adding it into another array. But there should be a more elegant solution for this. Do you know one?
NSArray implements the Key-Value Coding method valueForKey: in such a way that it returns a new array. The new array contains the results of asking each object in the original array for the specified value. In this case, NSNumber has its stringValue, so all you have to do is:
NSArray * b = [a valueForKey:#"stringValue"];
Plain old fast enumeration (or enumerateObjectsUsingBlock:) wouldn't be a terrible solution, though. NSArray's implementation of valueForKey: most likely uses a for loop internally, and that would be pretty readily understood by anyone who reads it later.
I tried storing a selector(SEL) in a NSMutableDictionary and it caused a crash, probably because the dictionary tries to dereference it as an object pointer. What is the standard recipe for storing non-objects in a dictionary?
You can convert selectors to NSString using NSStringFromSelector() and you can go back the other way with NSSelectorFromString().
SEL aSel = #selector(takeThis:andThat:);
[myDict setObject:NSStringFromSelector(aSel) forKey:someKey];
SEL original = NSSelectorFromString([myDict objectForKey:someKey]);
Try using a NSMapTable with NSObjectMapKeyCallBacks and NSNonOwnedPointerMapValueCallBacks. This works like a NSMutableDictionary but allows any pointers as values, not just objects.
You also could store the selector in a NSInvocation object and use that with a regular dictionary. If you need to store more than the Selector (target, parameters and so on) this is probably the better solution.
Wrap them into objects.
I want to use the object's reference value as a key into a dictionary, as opposed to a copy of value of the object. So, I essentially want to store an object associated with a particular instance of another object in a dictionary and retrieve that value later.
Is this possible? Is it completely against the idea of NSDictionary? I can tell that I am probably approaching this the wrong way because the dictionary wants me to implement NSCopying on the object itself, which doesn't really make sense in terms of what I'm doing. I can see that what I should really be doing is wrapping the pointer value, but that seems a little mad.
Advice would be appreciated.
I think you can use [NSValue valueWithPointer:object].
NSMutableDictionary has been designed to only deal with Objective-C object instances. For example, when you call setObject:forKey: method calls copyWithZone: on the key and retain on the value.
If you want to have a dictionary structure and to be able to deal with arbitrary key and value, then you can go with CFMutableDictionary. You can describe precisely what is done with key and values; it is flexible enough to deal with arbitrary pointer or event char * strings.
This did the trick for me
aDictionary[#((intptr_t)object)] = ...;
You can use the address in memory of myObejct as a key in myDictionary
NSString *myObject_addressInMemory = [NSString stringWithFormat:#"%p", myObject];
myDictionary[myObject_addressInMemory] = someValue;
I need to cast a boolean as an object, or NSKeyedArchiver throws a memory access error. What's the best way to do this?
How about encodeBool:forKey: instead?
Further to NSD's answer, in a general sense: Cocoa often requires actual objects for various methods. When the type you have is an ordinal type, such as int, BOOL, or float, you can wrap it in an NSNumber. For other types, you may need to wrap it in an NSValue or NSData (which is essentially an arbitrary binary buffer of a given length).