[iOS]用instancetype代替id作返回类型有什么好

系统 2426 0

苹果在iOS 8中全面使用instancetype代替id

Steven Fisher:只要一个类返回自身的实例,用instancetype就有好处。

      
        
          @interface 
          
            Foo:
            
              NSObject 
              
                - 
                
                  (
                  
                    id
                    
                      )
                      
                        initWithBar
                        
                          :(
                          
                            NSInteger
                            
                              )
                              
                                bar
                                
                                  ; 
                                  
                                    // initializer 
                                    
                                      + 
                                      
                                        (
                                        
                                          id
                                          
                                            )
                                            
                                              fooWithBar
                                              
                                                :(
                                                
                                                  NSInteger
                                                  
                                                    )
                                                    
                                                      bar
                                                      
                                                        ; 
                                                        
                                                          // convenience constructor 
                                                          
                                                            @end 
                                                          
                                                        
                                                      
                                                    
                                                  
                                                
                                              
                                            
                                          
                                        
                                      
                                    
                                  
                                
                              
                            
                          
                        
                      
                    
                  
                
              
            
          
        
      
    

对于简易构造函数(convenience constructor),应该总是用instancetype。编译器不会自动将id转化为instancetype。id是通用对象,但如果你用instancetype,编译器就知道方法返回什么类型的对象。

这个问题可不只有学术意义,比如,[[NSFileHandle fileHandleWithStandardOutput] writeData:formattedData]在Mac OS X(只在该OS版本)中会报错“Multiple methods named 'writeData:' found with mismatched result, parameter type or attributes.”原因是NSFileHandle和NSURLHandle都提供writeData:方法。由于[NSFileHandle fileHandleWithStandardOutput] 返回的类型是id,编译器并不确定请求了哪个类的writeData:方法。

你可以用

      
        
          [(
          
            NSFileHandle 
            
              *
              
                )[
                
                  NSFileHandle 
                  
                    fileHandleWithStandardOutput
                    
                      ] 
                      
                        writeData
                        
                          :
                          
                            formattedData
                            
                              ]; 
                            
                          
                        
                      
                    
                  
                
              
            
          
        
      
    

      
        
          NSFileHandle 
          
            *
            
              fileHandle 
              
                = 
                
                  [
                  
                    NSFileHandle 
                    
                      fileHandleWithStandardOutput
                      
                        ]; 
                        
                          [
                          
                            fileHandle 
                            
                              writeData
                              
                                :
                                
                                  formattedData
                                  
                                    ]; 
                                  
                                
                              
                            
                          
                        
                      
                    
                  
                
              
            
          
        
      
    

来绕过。

当然,更好的方法是声明fileHandleWithStandardOutput的返回类型为instancetype。(注意:这段样例代码在iOS中并不会报错,因为iOS中只有NSFileHandle提供writeData:方法。但length等方法则会,UILayoutSupport会返回CGFloat,而NSString则会返回NSUInteger)

initializer的情况更复杂,当你输入

      
        
          - 
          
            (
            
              id
              
                )
                
                  initWithBar:
                  
                    (
                    
                      NSInteger
                      
                        )
                        
                          bar 
                        
                      
                    
                  
                
              
            
          
        
      
    

编译器会假设你输入了

      
        
          - 
          
            (
            
              instancetype
              
                )
                
                  initWithBar:
                  
                    (
                    
                      NSInteger
                      
                        )
                        
                          bar 
                        
                      
                    
                  
                
              
            
          
        
      
    

对于ARC而言,这是必须的。 Clang Language Extensions 的相关结果类型(Related result types)也讲到了这一点。也许别人会据此告诉你不必使用instancetype,但我建议你用它。下面解释我为什么如此建议。

使用instancetype有三点好处:

1、明确性。代码只做你让它做的事,而不是其他。

2、程式化。你会养成好习惯,这些习惯在某些时候会很有用,而且肯定有用武之地。

3、一致性。让代码可读性更好。

明确性

用instancetype代替id作为返回值的确没有 技术上的好处 。但这是因为编译器自动将id转化成了instancetype。你以为init返回的值类型是id,其实编译器返回了instancetype。

这两行代码对于编译器来说是 一样 的:

      
        
          - 
          
            (
            
              id
              
                )
                
                  initWithBar:
                  
                    (
                    
                      NSInteger
                      
                        )
                        
                          bar
                          
                            ; 
                            
                              - 
                              
                                (
                                
                                  instancetype
                                  
                                    )
                                    
                                      initWithBar:
                                      
                                        (
                                        
                                          NSInteger
                                          
                                            )
                                            
                                              bar
                                              
                                                ; 
                                              
                                            
                                          
                                        
                                      
                                    
                                  
                                
                              
                            
                          
                        
                      
                    
                  
                
              
            
          
        
      
    

但在你眼里,这两行代码却不同。你不该学着忽视它。

模式化

在使用init等方法时的确没有区别,但在定义简易构造函数时就有区别了。

这两行代码并不等价:

      
        
          + 
          
            (
            
              id
              
                )
                
                  fooWithBar:
                  
                    (
                    
                      NSInteger
                      
                        )
                        
                          bar
                          
                            ; 
                            
                              + 
                              
                                (
                                
                                  instancetype
                                  
                                    )
                                    
                                      fooWithBar:
                                      
                                        (
                                        
                                          NSInteger
                                          
                                            )
                                            
                                              bar
                                              
                                                ; 
                                              
                                            
                                          
                                        
                                      
                                    
                                  
                                
                              
                            
                          
                        
                      
                    
                  
                
              
            
          
        
      
    

如果用instancetype作为函数的返回类型,就不会出错。

一致性:

最后,想象把所有东西放到一起时的情景:你想要一个init方法和一个简易构造函数。

如果你用id来作为init函数的返回类型,最终代码如下:

      
        
          - 
          
            (
            
              id
              
                )
                
                  initWithBar:
                  
                    (
                    
                      NSInteger
                      
                        )
                        
                          bar
                          
                            ; 
                            
                              + 
                              
                                (
                                
                                  instancetype
                                  
                                    )
                                    
                                      fooWithBar:
                                      
                                        (
                                        
                                          NSInteger
                                          
                                            )
                                            
                                              bar
                                              
                                                ; 
                                              
                                            
                                          
                                        
                                      
                                    
                                  
                                
                              
                            
                          
                        
                      
                    
                  
                
              
            
          
        
      
    

但如果你用instancetype,代码如下:

      
        
          - 
          
            (
            
              instancetype
              
                )
                
                  initWithBar:
                  
                    (
                    
                      NSInteger
                      
                        )
                        
                          bar
                          
                            ; 
                            
                              + 
                              
                                (
                                
                                  instancetype
                                  
                                    )
                                    
                                      fooWithBar:
                                      
                                        (
                                        
                                          NSInteger
                                          
                                            )
                                            
                                              bar
                                              
                                                ; 
                                              
                                            
                                          
                                        
                                      
                                    
                                  
                                
                              
                            
                          
                        
                      
                    
                  
                
              
            
          
        
      
    

代码更加一致,可读性更强。它们返回相同的东西,这一点一目了然。

结论

除非你有意为旧编译器写代码,不然你在合适的时候都应该用instancetype。

在写一条返回id的消息前,问自己:这个类返回实例吗?如果返回,用instancetype。

肯定有需要返回id的时候,但你用instancetype的频率应该会更高。

本答案摘自:http://zhuanlan.zhihu.com/Foundation/19569459

原帖: objective c - Would it be beneficial to begin using instancetype instead of id?

注意:我也是刚入门而已,如果翻译的术语与通行术语不一致,敬请告知;如果选取的翻译内容有误或过时,敬请告知,谢谢。

[iOS]用instancetype代替id作返回类型有什么好处?


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论