Reputation: 11920
Here are a few methods from some Apple classes:
- (NSManagedObject *)objectWithID:(NSManagedObjectID *)objectID;
- (UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;
+ (id)insertNewObjectForEntityForName:(NSString *)entityName inManagedObjectContext:(NSManagedObjectContext *)context
It is reasonable to expect all of these methods to return subclasses of the return type. Due to this the returned object is often assigned to a variable of the expected type, eg:
BCCustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[BCCustomTableViewCell cellIdentifier]];
This makes the compiler unhappy; a cast solves this, but casting like this is dirty:
BCCustomTableViewCell *cell = (id)[tableView dequeueReusableCellWithIdentifier:[BCCustomTableViewCell cellIdentifier]];
However, when the return type is id
, this cast can be removed, albeit at the cost of some type safety, resulting in my code being cleaner:
BCPerson *person = [NSEntityDescription insertNewObjectForEntityForName:BCPersonEntityName inManagedObjectContext:context];
Personally, I prefer it when the return type is id
. Is there any rationale that Apple used for choosing one approach over the other, or is it simply due to the preference of the developer who wrote the methods?
Upvotes: 4
Views: 559
Reputation: 15857
Casting is dirty, but having the method return id
is dirtier, since there may be hidden danger lurking beneath, which the compiler has no chance to warn you about. Doing the cast is just saying to the compiler 'you've warned me, now let me face the peril'.
Upvotes: 1
Reputation: 5346
If the return type is id
then surely the method definition is less helpful? You could receive any type of object, and there could be no compile-time type checking.
In the end, setting an subclass object just causes a compiler warning, which is a preferable situation to a potential bug caused by a typo, or misreading the documentation for that matter.
Upvotes: 1
Reputation: 16941
I really prefer the casting. If you return id
from these methods, the compiler will not warn you at all since it can't know what will be returned there. If you cast the return value correctly (and not cast to id
), then you can be sure that you've done it right if you don't get a warning. All it takes is to write one class name more.
BCCustomTableViewCell *cell = (BCCustomTableViewCell *)[tableView dequeue...];
The rationale of not returning id
is that you don't return just anything, but a given class and its subclasses. From this example method, you always get a table view cell, you can rely on it responding to certain methods (unless you mess up your subclass badly, that is). If you return id
you can't rely on anything, plus the compiler won't warn you.
Edit: I'm only referring to the instance methods, not the class methods. Williham explains that difference.
Upvotes: 2
Reputation: 29019
In the three examples you describe, two different principles are at work:
In the two first, Apple wants you to use a cast as a "I know what I'm doing" sort of thing: When you are accessing a generic object through an identifier, you might end up being surprised by the class of the return value, unless you know what you're doing.
In the latter example, the method is essentially a factory method, equivalent to alloc init
, and in most cases you had better know what it is you are making.
In other words, to answer your question:
For a factory method, id
, for a getter, the same as the setter.
Upvotes: 4