Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Yes, there are benefits to using <code>instancetype</code> in all cases where it applies. I'll explain in more detail, but let me start with this bold statement: Use <code>instancetype</code> whenever it's appropriate, which is whenever a class returns an instance of that same class.</p> <p>In fact, here's what Apple now says on the subject:</p> <blockquote> <p>In your code, replace occurrences of <code>id</code> as a return value with <code>instancetype</code> where appropriate. This is typically the case for <code>init</code> methods and class factory methods. Even though the compiler automatically converts methods that begin with “alloc,” “init,” or “new” and have a return type of <code>id</code> to return <code>instancetype</code>, it doesn’t convert other methods. <strong>Objective-C convention is to write <code>instancetype</code> explicitly for all methods.</strong></p> </blockquote> <ul> <li>Emphasis mine. Source: <a href="https://developer.apple.com/library/ios/releasenotes/ObjectiveC/ModernizationObjC/AdoptingModernObjective-C/AdoptingModernObjective-C.html#//apple_ref/doc/uid/TP40014150-CH1-SW11" rel="nofollow noreferrer">Adopting Modern Objective-C</a></li> </ul> <p>With that out of the way, let's move on and explain why it's a good idea.</p> <p>First, some definitions:</p> <pre><code> @interface Foo:NSObject - (id)initWithBar:(NSInteger)bar; // initializer + (id)fooWithBar:(NSInteger)bar; // class factory @end </code></pre> <p>For a class factory, you should <strong>always</strong> use <code>instancetype</code>. The compiler does not automatically convert <code>id</code> to <code>instancetype</code>. That <code>id</code> is a generic object. But if you make it an <code>instancetype</code> the compiler knows what type of object the method returns.</p> <p>This is <strong>not</strong> an academic problem. For instance, <code>[[NSFileHandle fileHandleWithStandardOutput] writeData:formattedData]</code> will generate an error on Mac OS X (<strong>only</strong>) <strong>Multiple methods named 'writeData:' found with mismatched result, parameter type or attributes</strong>. The reason is that both NSFileHandle and NSURLHandle provide a <code>writeData:</code>. Since <code>[NSFileHandle fileHandleWithStandardOutput]</code> returns an <code>id</code>, the compiler is not certain what class <code>writeData:</code> is being called on.</p> <p>You need to work around this, using either:</p> <pre><code>[(NSFileHandle *)[NSFileHandle fileHandleWithStandardOutput] writeData:formattedData]; </code></pre> <p>or:</p> <pre><code>NSFileHandle *fileHandle = [NSFileHandle fileHandleWithStandardOutput]; [fileHandle writeData:formattedData]; </code></pre> <p>Of course, the better solution is to declare <code>fileHandleWithStandardOutput</code> as returning an <code>instancetype</code>. Then the cast or assignment isn't necessary.</p> <p>(Note that on iOS, this example won't produce an error as only <code>NSFileHandle</code> provides a <code>writeData:</code> there. Other examples exist, such as <code>length</code>, which returns a <code>CGFloat</code> from <code>UILayoutSupport</code> but a <code>NSUInteger</code> from <code>NSString</code>.)</p> <p><strong><em>Note</strong>: Since I wrote this, the macOS headers have been modified to return a <code>NSFileHandle</code> instead of an <code>id</code>.</em></p> <p>For initializers, it's more complicated. When you type this:</p> <pre><code>- (id)initWithBar:(NSInteger)bar </code></pre> <p>…the compiler will pretend you typed this instead:</p> <pre><code>- (instancetype)initWithBar:(NSInteger)bar </code></pre> <p>This was necessary for ARC. This is described in Clang Language Extensions <a href="http://clang.llvm.org/docs/LanguageExtensions.html#related-result-types" rel="nofollow noreferrer">Related result types</a>. This is why people will tell you it isn't necessary to use <code>instancetype</code>, though I contend you should. The rest of this answer deals with this.</p> <p>There's three advantages:</p> <ol> <li><strong>Explicit.</strong> Your code is doing what it says, rather than something else.</li> <li><strong>Pattern.</strong> You're building good habits for times it does matter, which do exist.</li> <li><strong>Consistency.</strong> You've established some consistency to your code, which makes it more readable.</li> </ol> <h2>Explicit</h2> <p>It's true that there's no <em>technical</em> benefit to returning <code>instancetype</code> from an <code>init</code>. But this is because the compiler automatically converts the <code>id</code> to <code>instancetype</code>. You are relying on this quirk; while you're writing that the <code>init</code> returns an <code>id</code>, the compiler is interpreting it as if it returns an <code>instancetype</code>.</p> <p>These are <em>equivalent</em> to the compiler:</p> <pre><code>- (id)initWithBar:(NSInteger)bar; - (instancetype)initWithBar:(NSInteger)bar; </code></pre> <p>These are not equivalent to your eyes. At best, you will learn to ignore the difference and skim over it. <strong>This is not something you should learn to ignore.</strong></p> <h2>Pattern</h2> <p>While there's no difference with <code>init</code> and other methods, there <strong>is</strong> a difference as soon as you define a class factory.</p> <p>These two are not equivalent:</p> <pre><code>+ (id)fooWithBar:(NSInteger)bar; + (instancetype)fooWithBar:(NSInteger)bar; </code></pre> <p>You want the second form. If you are used to typing <code>instancetype</code> as the return type of a constructor, you'll get it right every time.</p> <h2>Consistency</h2> <p>Finally, imagine if you put it all together: you want an <code>init</code> function and also a class factory.</p> <p>If you use <code>id</code> for <code>init</code>, you end up with code like this:</p> <pre><code>- (id)initWithBar:(NSInteger)bar; + (instancetype)fooWithBar:(NSInteger)bar; </code></pre> <p>But if you use <code>instancetype</code>, you get this:</p> <pre><code>- (instancetype)initWithBar:(NSInteger)bar; + (instancetype)fooWithBar:(NSInteger)bar; </code></pre> <p>It's more consistent and more readable. They return the same thing, and now that's obvious.</p> <h2>Conclusion</h2> <p>Unless you're intentionally writing code for old compilers, you should use <code>instancetype</code> when appropriate.</p> <p>You should hesitate before writing a message that returns <code>id</code>. Ask yourself: Is this returning an instance of this class? If so, it's an <code>instancetype</code>.</p> <p>There are certainly cases where you need to return <code>id</code>, but you'll probably use <code>instancetype</code> much more frequently.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload