This enhances type safety.
In the old days, initializers just returned an object of type id (any object).
With regular initializers (those starting with "init", "alloc", or "new"), this is usually not a problem. The compiler automatically infers the type returned by it and, therefore, restricts any method calls to the object to instances of this class.
However, this was a problem with static convenience initializers or "factory methods" that did not necessarily conform to the same naming convention, so he could not apply the same type of security.
This means with a class like this:
@interface Foo : NSObject +(id) aConvenienceInit; @end
The compiler will accept this code:
NSArray* subviews = [Foo aConvenienceInit].subviews;
Why? Since the returned object can be any object, therefore, if you try to access the UIView property, there is no type security there to stop you.
However, now with instancetype result you are returning is of the type of your given instance. Now with this code:
@interface Foo : NSObject +(instancetype) aConvenienceInit; @end ... NSArray* subviews = [Foo aConvenienceInit].subviews;
You will get a compiler warning saying that the subviews property subviews not a member of Foo* :
Although it is worth noting that the compiler automatically converts the return type from id to instancetype if your method starts with "alloc", "init" or "new" - but, nevertheless, with instancetype , where you can get into this good habit.
See Apple docs in instancetype more details.