Passing an int as "object" in NSNotification - objective-c

I'm trying to send an int (which is defined in an enum) as the object in an NSNotification.
I can't do this, because I'll get an EXC_BAD_ACCESS error thrown when trying to access the object in the notify: method of the observer, since int is not of type id (I think?).
My current solution is to cast the int to an NSNumber (by using numberWithInt:). While this works it doesn't feel right or clean.
So the question is: what is the correct way to pass an int as the "object" of an NSNotification?
I guess this actually has nothing to do with this specific case, but a Cocoa thing in general :-)

You're not casting to NSNumber... you're creating a NSNumber object and setting the contents (or value) of it to your int.
And Objective C objects are what you can pass in the userInfo dictionaries of NSNotifications, so what you are doing is absolutely correct.
Now as to the crash, please edit your question to show code as to how you are creating and posting your NSNotification and what the method is that actually handles the received NSNotification you sent.

id is the generic type for objects. So if the method expects an id, you can't pass an int —it's not an object. The optimal object for numeric values is NSNumber, so you're doing it correctly.
A side note: don't use the term "casting" here. You're not casting, you're creating an object.

The correct way it what you are doing, create an NSNumber instance and pass it.
As #Michael say, you are not casting it, you are creating an instance.

Related

Objective-C id & NSObject

I understand that id is for any Object type even objects that do not inherit NSObject such as things from Cocoa. I have been told to almost always use id but what if I were making an API and had a method that I wanted to make it clear that it should only take a certain type of object such an object called Animal, would I still use
(id) animal
or would I do
(Animal) animal
Thanks so much!
id is a generic pointer to an object -- it's like void *, except that the pointer must point to an Objective-C object. So yes, you could use id in most situations where a more specific object pointer type would work, but it's usually better to use the more specific type:
- (id)animal; // OK if 'animal' could be any type of object
- (Animal*)animal; // much better if you know that 'animal' points to an object of type 'Animal'
You'll find plenty of examples if you look at any Cocoa or Cocoa Touch class. Let's look at a little bit of UIView:
- (BOOL)isDescendantOfView:(UIView *)view; // returns YES for self.
- (UIView *)viewWithTag:(NSInteger)tag; // recursive search. includes self
As you can see, the first method takes a UIView* as a parameter. If you try to pass something other than a pointer to an instance of UIView, the compiler will complain.
The second method returns a UIView*, and you can use the result directly as the receiver of other messages that UIView understands:
[[topView viewWithTag:someTag] removeFromSuperview];
Being specific about the types of parameters and return values lets the compiler help you make sure that you're sending appropriate messages to your objects and getting appropriate values back.
You can use any type starting from Animal and then up through inheritance chain to NSObject and id. Any would be valid. But in most cases you need to use just Animal because this is the very type you need to work with

Should I be casting when returning id from an objective-c method or not?

For the Objective-C gurus:
Suppose I have a simple method like so:
-(id)getValue{ return [NSNumber numberWithDouble:5.0]; }
Now, suppose within some other method I call the (id)getValue method like so:
NSNumber* myValue = [self getValue];
or what if I call it like this instead:
NSNumber* myValue = (NSNumber*)[self getValue];
The question is: Obviously these lines are equivalent but one of them utilizes an explicit cast. So what is the correct or best-practice way of doing this. It seams to me the cast is unnecessary since when it is placed in the pointer myValue, it will be type-safe at this point anyways (which is something I want) so the cast is basically pointless.
Let me just add that I'm sure people will point out: Why don't you just return (NSNumber*) from the getValue method but in my case I want to have the flexibility to return whatever I want much like the built in NSDictionary class returns id when you call: objectForKey because it allows you to place any type of NSObject or subclass inside of it. In other words my getValue method will not always be returning an NSNumber. Also consider this example is contrived because I am just concerned about whether to cast or not.
Thank you in advance,
-Ralph
The only reason to cast objects is to make the compiler happy. (Sometimes it also helps readability.) For example, you have to cast when making a property access directly on an object you're getting out of an array or dictionary:
((Foo *)[myArray objectAtIndex:0]).bar;
If you don't do the cast, the compiler can't do the property lookup, and will complain.
When you're getting an object from a method that returns id, it's impossible for the compiler to know what its actual type is. There isn't really any "type-safety", because id is a generic pointer; all the compiler can and will enforce is that the method says it returns some Objective-C object. It is perfectly happy to assign a generic pointer to any typed pointer.* (This is actually an advantage for containers, obviously.) Since the type of the variable to which you're assigning already documents the actual return type, I'd say there's no need for the cast.
As an aside, you shouldn't be calling your method getX. That has a specific meaning in Cocoa; methods which "get" something pass in a pointer to a pointer, which is then filled by the method. See -[NSArray getObjects:range:] as an example.
*The type will be enforced at run-time, of course, in the sense that sending messages to which the object does not respond will cause an error.

Instance pointers in an array

I'm trying to save pointers of class instances into a mutable array. I'm able to do this but getting them back into use seems to be a problem. The next is how I inserted the pointers into the array:
Class *class = [Class new];
/* Do something with the instance */
[instanceArray addObject:class];
I am able to retrieve the wanted index from the array but when I try to access the instance variables etc. I only get compiler shouting at me or sometimes I get every variable as zero.
How am I supposed to get the instance back to use from the array? I know they are pointers but playing with them didn't seem to work.
Using addObject: the element is inserted at the end of the array. To retrieve it you can use -[NSArray objectAtIndex:]
Pointer arithmetic works in C since then your array is just a pointer to the first index, and array[i] is the same as *(array + i). In Objective-C this may still be done, however you're using an NSArray object. Now you don't have a pointer to the first object anymore, but to the instance of the class. To retrieve the objects stored in the array, you'll have to call the corresponding methods.
EDIT
So you are able to retrieve it from the array and then your pointer is not nil, so you do have access to the object. You know in Objective-C, all instance variables are private so you can't access them from outside. You'd have to declare them as properties first (please refer to the documentation). Also, when you declare a variable to be of type id, accessing a property with dot-syntax doesn't work, it will cause a compiler error.

Incompatible Type for Argument 1 Objective-C

I have a function that sets an entity within a Core Data store. I used to have all values it would be storing as type double, however now I must make it accommodate NSStrings as well. Consequently, I changed the type of the parameter the function takes in, to an id type. However, now I get the error:
error: incompatible type for argument 1 of 'numberWithDouble:'
...at the following lines:
//...
[dfm setTimeStamp:[NSNumber numberWithDouble:value]];
//...
[[fetchedObjects objectAtIndex:0] setValue:[NSNumber numberWithDouble:value] forKey:#"timeStamp"];
//...
Apparently it doesn't like the [NSNumber numberWithDouble:value] segment of each line. I was contemplating making a container class that holds an NSNumber type (doesn't Apple already have a class like this?) to get around this problem, but I thought that there has to be an easier way I am not thinking of (besides duplicating the function and changing the type of the value parameter). Any ideas? Thanks in advance!
EDIT:
Here is the function declaration:
-(void)setItemInDFMWhilePreservingEntityUniquenessForItem:(attribute)attr withValue:(id)value
attribute is merely an enum which specifies which entity to store within. The problem is that the compiler is giving me problems with value being of type id, theoretically I can pass in anything I want, and I believe the way I have it I am implying that I will be passing it as an NSNumber, but the compiler doesn't like that as that is not actually a class instance I suppose?
The problem is that the compiler is
giving me problems with value being of
type id, theoretically I can pass in
anything I want, and I believe the way
I have it I am implying that I will be
passing it as an NSNumber, but the
compiler doesn't like that as that is
not actually a class instance I
suppose?
By declaring value as id, you can pass any object you want. But why do you "suppose" that NSNumber isn't an object, when it's clearly documented as being an object? The warning isn't about passing an NSNumber instance when you've declared value as an id - that's perfectly valid, because id means "any object," and an NSNumber instance is an object. The warning comes from calling +numberWithDouble:, a method that takes a double for its first argument, and passing it value, which is declared as id - i.e. an object. You can't pass an object to a method that expects a double.
Your proposed solution, typecasting value with (NSInteger)value will silence the warning, but it won't fix the problem. The typecast simply converts the memory address the object pointer targets to an integer value. If (as your edit suggests) value is already an NSNumber object, what do you hope to gain by creating another one, or by typecasting its memory address to an integer? Just do:
[dfm setTimeStamp:value];
The problem lies with the value variable. It should be declared as a double (primitive) for this call to succeed.
edit: after rereading your question, do a check in the function on the type of value, if it is an NSString (use [value isKindOfClass:[NSString class]]) store it as such, if its not then its a double (if thats the only two types you are passing) and store it as such.
Can't you just pass the NSNumber instead of double?
Just realized that the call I was making (numberWithDouble:) was having the compiler check for a primitive, i.e. double. Changing it to the following worked like a charm:
[dfm setTimeStamp:[NSNumber numberWithInteger:(NSInteger)value]];
Thanks to those that responded!

Object pointer value as key into dictionary

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;