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.
Related
Coming from Java et al, I'm not clear on the difference between these two declarations:
#property (nonatomic, readwrite) NSInteger score;
#property (nonatomic, strong) NSMutableArray *cards;
Why is the pointer, *, not a requirement on both property declarations?
I've seen this a lot in local variables too:
- (void)viewDidLoad
{
[super viewDidLoad];
int foo = 1;
NSString *bar = #"foo";
}
What's the difference between static allocation of primitive type int and NS types?
Objective-C objects are always allocated on the heap, so you always access them through pointers. Variables of primitive (or struct) types can be, and typically are, allocated on the stack and accessed without pointers.
If you're familiar with Java, it's basically the same semantics. Primitive types are accessed and passed around by value, objects by reference. The difference is that ObjC has (by virtue of its C lineage) syntax explicitly marking that difference.
Type names that start with an uppercase prefix in Apple frameworks aren't all ObjC classes. NSInteger is a primitive type just like int, so you can and usually do use it without pointers.
pointer is always used for referring to something at the heap but not when you referring to something on the stack.But
for some primitive types and simple structure which are accessed via the stack so you don't need to use pointer..
NSInteger is a primitive type, that means it will be stored locally on the stack. there is no need to use a pointer to access it, but if you want to use pointer then you can.
You can have a pointer to an NSInteger if you really want to with following way:
NSInteger *pointerToProcessID = &yourNsintegervar;
If you look at the definition of NSInteger you'll see that it is a typedef for a simple integer. Basically, all the non-object types are stored as simple values, while the types that are complex objects are typically pointer properties. There are a couple reasons why these more complex objects are stored as pointers:
Using the value, itself, instead of the pointer would require copying (that is, if you use a pointer, you can put the object somewhere else and you only need to copy the much shorter address rather than all of the content that happens to be in that object, and hence it is more efficient that way).
When using a non-pointer type, it is necessary to know the required storage space, which works if you know the exact type of the object, but fails in the case of inheritance (e.g. an NSMutableArray may add additional fields to NSArray, for example. If you were to use NSArray instead of NSArray*, then assigning from an NSMutableArray would be broken, because the system would only have set aside enough space for the fields in the base class and not for the derived class. When using a pointer, however, since the pointer size is the same for both the base and derived types, one can assign the pointer for a derived type to a pointer to the base type, and still have things work correctly).
Note that it is possible and safe to use a pointer type with these primitive types, as well; however, this is not done for efficiency reasons (it would create additional allocation and dereferencing where not necessary).
I'm trying to teach myself objective-c using the big nerd ranch book, it is a really great book but certain aspects confuse me.
The current chapter is talking about using setValue:forKey function which I understand is a method defined in NSObject. The book says that you can use this on a c primitive like int or float and gives this example
I have a custom class called Appliance and in it is an integer instance variable called voltage that stores the voltage of the current appliance
I initialize a new appliance called a
appliance *a = [[appliance alloc]init];
[a setValue:[NSNumber numberWithInt:240] forKey:#"voltage"];
he then sets up a custom setter for voltage and logs the voltage when its called to prove it works
-(void)setVoltage:int(x) {
NSLog(#"setting voltage to %d",x);
voltage =x;
}
whats confusing me is that NSNumber numberWithInt returns a pointer to an NSNumber object thats stored on the heap correct? so then how does he log the integer stored in NSNumber using the %d token. I understand that would log an integer but isn't an object being passed in? furthermore I thought that since voltage was defined as an integer and not a pointer to something it couldn't hold the address to an object in its memory? or is NSNumber kind of forcing it to hold its memory address without actually having voltage being declared as a pointer?
sorry for the confusion this chapter basically kicked my butt.
The conversion between objects and scalar types is handled automatically by the Key-Value Coding methods. From the documentation:
The default implementations of valueForKey: and setValue:forKey:
provide support for automatic object wrapping of the non-object data
types, both scalars and structs.
Once valueForKey: has determined the specific accessor method or
instance variable that is used to supply the value for the specified
key, it examines the return type or the data type. If the value to be
returned is not an object, an NSNumber or NSValue object is created
for that value and returned in its place.
Similarly, setValue:forKey: determines the data type required by the
appropriate accessor or instance variable for the specified key. If
the data type is not an object, then the value is extracted from the
passed object using the appropriate -<type>Value method.
So in your case, intValue is applied automatically to the passed NSNumber
object, and the resulting integer is passed to setVoltage:.
You are correct in that you are creating an NSNumber instance and passing that. But, you're passing it to setValue:forKey: and it's doing some work for you. It's finding the appropriate setter method for voltage (setVoltage:), checking the data type and unboxing the number into an int before calling the setter.
This question already has answers here:
NSMutableArray - force the array to hold specific object type only
(12 answers)
Closed 9 years ago.
I'm programming on Objective C for the first time, coming from C++ (so far I like
the latter much better!). I have a question regarding mutable arrays, namely I want to create one with the specific type of one of my objects, 'CMParticle', instead of the generic ID type. To access data in my object from my mutable array, I have to cast it as one of my objects each time (which is I believe cumbersome) like so:
rij[0] = ((CMParticle *)particles[*pi]).crds[0] - ((CMParticle *)particles[*pj]).crds[0];
where 'particles' is my mutable array of CMParticle objects. I would rather do this
rij[0] = particles[*pi].crds[0] - particles[*pj].crds[0];
Prior to this I declare my mutable array like so:
particles = [NSMutableArray array];
It would be nice if I could declare this array with my type somehow so I don't have to typecast every time. Is there a way to do this?
What you're trying to do doesn't actually make sense in Objective C.
C++ containers are homogenous, but generic. You can have a vector<CMParticle>, or a vector<int>, and they're different types.
ObjC containers are heterogeneous. You just have an NSArray, and it can hold CMParticle objects, NSNumber objects, or anything else, all mixed up in one big array.
You generally don't need these casts at all. If you want to send a message to my_array[3], just do [my_array[3] doSomething:15]. Just like a higher-level language (Python, Ruby, Smalltalk, Javascript, etc.).
The only problem is that (unlike Python, etc.), there are a few cases where you do need the cast. Most critically (and annoyingly), if you want to access members directly, you have to cast first. This is one of the reasons that ObjC (unlike Python, etc.) encourages you to use #property and/or explicit accessors instead of directly accessing members. (Also, as a more minor annoyance, because variables have declared types, you can't just write tempval = my_array[3];, you have to specify the type, like: CMParticle *tempval = my_array[3].)
Another way to look at this: C++ extends C's static, weak type system to give you a stronger static type system; ObjC instead bolts on a separate dynamic type system (unfortunately leaving the existing C stuff unchanged, which is where the occasional problems come in).
You can pretty easily write your own NSMutableArray subclass that's generic (taking the class at runtime, unlike C++'s compile time, of course) and homogenous, but all that does is add restrictions; the elements will still be id everywhere. The only way around that is to write a custom class for each array: MutableCMParticleArray, MutableNSNumberArray, etc.
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).
When do you and when dont you need the * symbol (which is because in objective-c all variables like NSString are pointer variables)?
For example when do you need to do "NSString *" instead of just "NSString"?
In Objective-C, all object references are pointers, so you always need the pointer operator when you declare with an Objective-C object.
For other types, the use is exactly the same as in C. Use pointers when you want to pass data structures or primitive types by reference.
You use the asterisk for all Objective-C objects (such as NSDictionary, NSString, NSNumber).
For anything that is a primitive type (int, double, float) you don't need the asterisk. However, the NS prefix doesn't always mean that you must use an asterisk. Cocoa defines some structures (such as NSInteger, NSRect, NSPoint) that are are based on primitive types. You don't use the asterisk here either. An NSRect, for example, is just a structure of an NSPoint and NSSize, both of which are made up of 2 CGFloats (a primitive type).
You can pass a pointer to one of these primitive types or structures using the * notation.