Clang adds a keyword instancetype
that, as far as I can see, replaces id
as a return type in -alloc
and init
.
Is there a benefit to using instancetype
instead of id
?
Clang adds a keyword instancetype
that, as far as I can see, replaces id
as a return type in -alloc
and init
.
Is there a benefit to using instancetype
instead of id
?
There definitely is a benefit. When you use 'id', you get essentially no type checking at all. With instancetype, the compiler and IDE know what type of thing is being returned, and can check your code better and autocomplete better.
Only use it where it makes sense of course (i.e. a method that is returning an instance of that class); id is still useful.
You also can get detail at The Designated Initializer
**
INSTANCETYPE
** This keyword can only be used for return type, that it matches with return type of receiver. init method always declared to return instancetype. Why not make the return type Party for party instance, for example? That would cause a problem if the Party class was ever subclassed. The subclass would inherit all of the methods from Party, including initializer and its return type. If an instance of the subclass was sent this initializer message, that would be return? Not a pointer to a Party instance, but a pointer to an instance of subclass. You might think that is No problem, I will override the initializer in the subclass to change the return type. But in Objective-C, you cannot have two methods with the same selector and different return types (or arguments). By specifying that an initialization method return "an instance of the receiving object," you would never have to worry what happens in this situation. **
ID
** Before the instancetype has been introduced in Objective-C, initializers return id (eye-dee). This type is defined as "a pointer to any object". (id is a lot like void * in C.) As of this writing, XCode class templates still use id as the return type of initializers added in boilerplate code. Unlike instancetype, id can be used as more than just a return type. You can declare variables or method parameters of type id when you are unsure what type of object the variable will end up pointing to. You can use id when using fast enumeration to iterate over an array of multiple or unknow types of objects. Note that because id is undefined as "a pointer to any object," you do not include an * when declaring a variable or object parameter of this type.
Yes, there are benefits to using
instancetype
in all cases where it applies. I'll explain in more detail, but let me start with this bold statement: Useinstancetype
whenever it's appropriate, which is whenever a class returns an instance of that same class.In fact, here's what Apple now says on the subject:
With that out of the way, let's move on and explain why it's a good idea.
First, some definitions:
For a class factory, you should always use
instancetype
. The compiler does not automatically convertid
toinstancetype
. Thatid
is a generic object. But if you make it aninstancetype
the compiler knows what type of object the method returns.This is not an academic problem. For instance,
[[NSFileHandle fileHandleWithStandardOutput] writeData:formattedData]
will generate an error on Mac OS X (only) Multiple methods named 'writeData:' found with mismatched result, parameter type or attributes. The reason is that both NSFileHandle and NSURLHandle provide awriteData:
. Since[NSFileHandle fileHandleWithStandardOutput]
returns anid
, the compiler is not certain what classwriteData:
is being called on.You need to work around this, using either:
or:
Of course, the better solution is to declare
fileHandleWithStandardOutput
as returning aninstancetype
. Then the cast or assignment isn't necessary.(Note that on iOS, this example won't produce an error as only
NSFileHandle
provides awriteData:
there. Other examples exist, such aslength
, which returns aCGFloat
fromUILayoutSupport
but aNSUInteger
fromNSString
.)Note: Since I wrote this, the macOS headers have been modified to return a
NSFileHandle
instead of anid
.For initializers, it's more complicated. When you type this:
…the compiler will pretend you typed this instead:
This was necessary for ARC. This is described in Clang Language Extensions Related result types. This is why people will tell you it isn't necessary to use
instancetype
, though I contend you should. The rest of this answer deals with this.There's three advantages:
Explicit
It's true that there's no technical benefit to returning
instancetype
from aninit
. But this is because the compiler automatically converts theid
toinstancetype
. You are relying on this quirk; while you're writing that theinit
returns anid
, the compiler is interpreting it as if it returns aninstancetype
.These are equivalent to the compiler:
These are not equivalent to your eyes. At best, you will learn to ignore the difference and skim over it. This is not something you should learn to ignore.
Pattern
While there's no difference with
init
and other methods, there is a difference as soon as you define a class factory.These two are not equivalent:
You want the second form. If you are used to typing
instancetype
as the return type of a constructor, you'll get it right every time.Consistency
Finally, imagine if you put it all together: you want an
init
function and also a class factory.If you use
id
forinit
, you end up with code like this:But if you use
instancetype
, you get this:It's more consistent and more readable. They return the same thing, and now that's obvious.
Conclusion
Unless you're intentionally writing code for old compilers, you should use
instancetype
when appropriate.You should hesitate before writing a message that returns
id
. Ask yourself: Is this returning an instance of this class? If so, it's aninstancetype
.There are certainly cases where you need to return
id
, but you'll probably useinstancetype
much more frequently.Above answers are more than enough to explain this question. I would just like to add an example for the readers to understand it in terms of coding.
ClassA
Class B
TestViewController.m