How do you call setTag: for id type objects?
Also, if you don't want your compiler complaining and you know the type of the object, you can cast it.
[(UILabel *)objById setTag:5];
id is not exactly a class. It's a generic type which is used in Objective C for arbitrary object. E.g., method taking any object could look like this
-(void) doIt(id parameter);
So, saying that your object has type id adds no information.
But if you're absolutely certain your object responds to setTag, you can just do it: [object setTag:123].
Otherwise, just lookup documentation for the object's classs.
setTag should be assumed to be a method that belongs to UIView subclasses. If you are certain that the object in question is indeed a UIView subclass, you would call the method as normal: [someIdInstance setTag:5];
Based on your question, I'd presume you may not understand the significance of the id type. An object of type id may realistically be a pointer to any type of object. You have no guarantee that setTag: may in fact be defined for that object, which is typically why code that deals with id pointers performs steps like this:
id foo = [self getSomePointer];
if([foo respondsToSelector:#selector(setTag:)]) {
[foo setTag:4];
}
The code checks to see if the object even has the method before attempting to call it.
usually it goes like
object-type.tag = value;
like
button.tag = 50;
Related
I have an NSMutableArray of two different objects inside. I am trying to recognize the first object of the array and assign it properly. Here is the example code with my idea of
// I should declare a variable here, firstly I thought about "id someObject;"
// and assigning to it in if statement.
id someObject;
if ([[someArray objectAtIndex:0] isKindOfClass:[firstOpponent class]]) {
someObject = (firstOpponent*)[someArray objectAtIndex:0];
} else {
someObject = (secondOpponent*)[someArray objectAtIndex:0];
}
[someObject method]; // this is OK
someObject.position; // property 'position' not found on object of type '__strong id'
With the idea of declaring "id someObject;" before if statement there is some problem with properties. I read that it isn't possible, thats why I'm asking for other solutions.
Your if statement achieves nothing in respect of typing.
In Objective-C a cast on a reference type, such as (firstOpponent *), does nothing at runtime; it simply allows the compiler to produce better error messages.
In your code you cast, which tells the compiler the type of the reference, and then you immediately assign to a variable of type id - which is the most general/least specific object reference type - and the compiler now knows nothing about the contents of someObject other than it contains a reference to some object.
So your code is equivalent to:
id someObject;
someObject = someArray[0];
[someObject method]; // this is OK
someObject.position; // compile time error
When calling a method on a reference typed as id, in your case someObject, the compiler does no checking and simply allows the method call. At runtime a check is done to verify the actual object references supports the method, and if not a runtime error will occur and the application will be aborted.
However the compiler will only call a property on a object whose type it knows. This is because it needs to know the type to determine what method call to translate the property access into. In general, but not always, the property access:
object.property // read a value
object.property = value // write a value
translate into the method calls:
[object property]
[object setProperty:value]
So you can access the property by doing the translation yourself and writing one of the second pair. If at runtime the reference object does not support the property then you will get an error and your application will abort.
Another option is to define a protocol, say OpponentProtocol, which declares the methods and properties all opponent classes should implement, and then have both your opponent classes implement it. You may then declare:
id<OpponentProtocol> someObject;
where the type means "any object reference as long as it implements the protocol OpponentProtocol". With such a type the compiler knows how to translate a property access into the appropriate method call, so you can access OpponentProtocol properties on someObject.
HTH
You should create a protocol that your two classes can confirm to and use id < MY_PROTOCOL > instead of just id so the compiler knows what the class is capable of responding to.
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
From my understanding both of the following getter methods reference the actual object.
So what is the difference between the two?
When and why would you want to use the second getter method?
- (MyObject *)myObject
{
return _myObject;
}
- (void)getMyObject:(MyObject **)myObject
{
if (!myObject)
{
*myObject = _myObject;
}
}
You would not use the second one.
Unless you like confusing people/yourself at a later date by not following the standard conventions.
It would make more sense if there was another piece of data that could also be returned for example look at NSManagedObjectContext
- (BOOL)save:(NSError **)error
The important result of the method is YES/NO did it save, but then we can also get an NSError object to inspect if there was an error.
In Objective C, an "object" is a C pointer, so an object value is actually already the same as a structure reference (an opaque structure with hidden fields if you want the code to be portable between Objective C runtimes).
So there is no "versus".
YouR first example is both.
There are special situations when an algorithm needs a reference to a reference, or a pointer to a pointer, but not very commonly. That would be your second example.
I'm just trying to get my head around this type of syntax
I know that the
[instanceOfClass Method];
eg. [myImage setImage:[NSImage imageNamed:#"picture.jpg"]];
performs a method on the instance of the class.
but how does this work..
Variable = [Class methodName];
eg. int Value = [sender intValue];
can someone explain this to me. I get that the first example performs a method on instance of class, class or variable..
but how does the latter part work?
Thank you very much.
There are instance methods (defined with a -) and class methods (with a +). Instance methods are called in instances and class methods in classes.
- (void)instanceMethod;
+ (void)classMethod;
Apart from this, you example:
int Value = [sender intValue];
Seems to be an instance method. If it's inside an action, keep in mind sender is just an argument:
- (IBAction)startWork:(id)sender
{
...
}
The second example also performs a method on an instance of a class, but that method returns a value which is assigned to the value on the left side of the equation.
I'd recommend spending a little time reading the introduction provided by Apple. This specific question is discussed in this part of the document:
Like standard C functions, methods can return values. The following
example sets the variable isFilled to YES if myRectangle is drawn as a
solid rectangle, or NO if it’s drawn in outline form only.
BOOL isFilled;
isFilled = [myRectangle isFilled];
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.