What should be the return type when a method can return subclasses?

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 that all of these methods will return subclasses of the return type. In this regard, the returned object is often assigned to a variable of the expected type, for example:

 BCCustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[BCCustomTableViewCell cellIdentifier]]; 

This makes the compiler unhappy; casting 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, as a result of which my code becomes cleaner:

 BCPerson *person = [NSEntityDescription insertNewObjectForEntityForName:BCPersonEntityName inManagedObjectContext:context]; 

Personally, I prefer when the return type is id . Is there any rationale that Apple used to choose one approach over another, or is it just because of the preference of the developer who wrote the methods?

+4
source share
4 answers

In the three examples you describe, two different principles work:

In the first two cases, Apple wants you to use the cast as "I know what I'm doing": when you access a shared object through an identifier, you may be surprised at the class return value if you don't know what you are doing.

In the last example, the method is essentially a factory method equivalent to alloc init , and in most cases, you better know what you are doing.

In other words, to answer your question:

For the factory id method for the getter, the same as the installer.

+4
source

I really prefer casting. If you return the id from these methods, the compiler will not warn you at all, since it cannot know what will be returned there. If you return the return value correctly (and not added to id ), you can be sure that you did it correctly if you did not receive a warning. All that is required is to write another class name.

 BCCustomTableViewCell *cell = (BCCustomTableViewCell *)[tableView dequeue...]; 

The rationale for not returning an id is that you are returning nothing but this class and its subclasses. In this example, you always get a table cell, you can rely on it in response to certain methods (unless you mess up your subclass badly, that is). If you return id , you cannot rely on anything, plus the compiler will not warn you.

Edit: I mean only instance methods, not class methods. William explains this difference.

+2
source

If the return type is id , then of course the method definition is less useful? You can get any type of object, and there can be no compilation type check.

In the end, setting the subclass object only causes a compiler warning, which is the preferred situation for a potential typo error or misinterpretation of the documentation.

+1
source

Casting is dirty, but the return of the id method is more dirty, because under it there may be a hidden danger that the compiler cannot warn you about. The cast simply tells the compiler: "You warned me, now let me run into danger."

+1
source

Source: https://habr.com/ru/post/1334477/


All Articles