为什么你需要使用instancetype而不是id

四年前Clang添加了关键字instancetype,目的在于取代-alloc和-init等方法的返回类型id,那么使用instancetype到底比id好在哪里?

instancetype宣言

不管何时,只要一个class要返回它相同的类实例,使用instancetype都是更加合适的。

我们知道,当调用类中(或者子类)的-alloc、-init或者class factory(+)方法,使用instancetype关键字会返回它的类实例。在这种情况下用instancetype而不是id有100个好处。

苹果也这样说:

In your code, replace occurrences of id as a return value with instancetype where appropriate. This is typically the case for init 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 id to return instancetype, it doesn’t convert other methods. Objective-C convention is to write instancetype explicitly for all methods.

更加有力的证据:Adopting Modern Objective-C

为什么?

首先你可能需要知道编译器会做什么?

@interface Foo:NSObject

// initializer

- (id)initWithBar:(NSInteger)bar;

// convenience constructor

+ (id)fooWithBar:(NSInteger)bar;

@end

对于convenience constructor,你必须要使用instancetype,因为编译器不会把id自动转换成instancetype。

而对于initializer,当你的代码是这样的:

// initializer

- (id)initWithBar:(NSInteger)bar;

ARC下,编译器会把它变成这样:

// initializer

- (instancetype)initWithBar:(NSInteger)bar;

这也是为什么有人告诉你用instancetype是没有必要的,但是我建议你使用instancetype,原因有三:

  1. 明确性:你的代码含义明确,绝不会做其他事。
  2. 模式化:你建立了一个良好的习惯,这确实是很重要的。
  3. 一致性:让你的代码更一致,并且增加可读性。

1、明确性

 

在-init方法中返回instancetype确实是没有太多的好处,这是因为编译器会自动把id转换成instancetype。

这对于编译器来讲是等价的:

- (id)initWithBar:(NSInteger)bar;

- (instancetype)initWithBar:(NSInteger)bar;

但是至少这在你眼中是不同的。

2、模式化

虽然对init或者其他方法,返回id和instancetype没什么不同,但是在convenient constructor(+)方法中他们是有区别的:

+ (id)fooWithBar:(NSInteger)bar;

+ (instancetype)fooWithBar:(NSInteger)bar;

你必须要用第二条才能保证你每次运行的结果正确,为什么?
考虑这样的情况:

然后我们这样调用:

发现x出现编译警告,因为我们的+factoryMethodA返回的是instancetype,它表示的是MyObject*,因为MyObject没有-count方法,所以出现了编译警告。

然而,因为我们的+factoryMethodB返回的是id,编译器没有在y行给警告,因为Objc语言动态类型和动态绑定的特性,id可能是任何class,又因为-count方法可能于存在某个类的某个地方,因此对于编译器而言,+factoryMethodB方法返回的东西是可能实现-count方法的。

3、一致性

 

在init中可以返回id,因此你可能会这样写:

- (id)initWithBar:(NSInteger)bar;

+ (instancetype)fooWithBar:(NSInteger)bar;

但是如果你使用instancetype,结果会是这样:

- (instancetype)initWithBar:(NSInteger)bar;

+ (instancetype)fooWithBar:(NSInteger)bar;

这样看起来更加一致并且可读性更高。他们返回同样的东西,但是后者看起来更明显,不是吗?

结论

当要返回id类型的时候,你应该思考它是否会返回一个类的实例,如果是,请使用instancetype。

时间: 2024-08-03 10:12:12

为什么你需要使用instancetype而不是id的相关文章

为什么表单中post接受数据是获取name值而不是id值

感谢解惑者:http://blog.csdn.net/u013451157/article/details/78503831 表单(form)的控件名,提交的数据都用控件的name而不是id来控制. 因为有许多name会同时对应多个控件,比如checkbox和radio:而id必须是全文档中唯一的. 此外浏览器会根据name来设定发送到服务器的request.如果用id,服务器是无法得到数据的. name是表单元素里才有的属性. <form name="myForm">&l

为什么在写css时尽量使用class而不使用id来标记元素

虽然一直以来写css代码都是用得class类名来标记元素,但这更多是自己的习惯,今天对这个问题做个分析总结. 下面是为什么这么做的具体原因 一:元素的class类名可以有很多个,而id名只能有一个.通过给一个元素添加多个class类名,可以更为灵活的控制元素的样式 <div class="size color"></div> //尺寸为200 * 200,背景颜色为pink .size { width: 200px; height: 200px; } .colo

IOS升级之 Objective-c新特性

采用现代objective - c 来源:http://www.cnblogs.com/chensheng12330/p/3950004.html 多年来,objective - c语言已经发展和演变. 虽然核心概念和实践保持不变,部分语言经历了重大的变化和改进. 这些现代化提高类型安全.内存管理.性能.和其他方面的objective - c,使你更容易编写正确的代码. 采用这些变化是很重要的在你的现有的和未来的代码来帮助它变得更加一致的,可读的,有弹性. Xcode提供了一个工具来帮助使你的一

Objective-C编码规范[译]

原文链接 : The official raywenderlich.com Objective-C style guide 原文作者 : raywenderlich.com Team 译文出自 : raywenderlich.com Objective-C编码规范 译者 : Sam Lau 因为我正在准备模仿饿了么这个app,到时可能有些iOS开发人员參与进来. 这时假设每一个人的Objective-C编码风格都不一样,这样不易于保持代码一致性和难以Code Review.所以我在网上搜索到 T

Adopting Modern Objective-C 译文

这些年来,Objective-C在不断的发展和进化.尽管最核心的概念和实践都是一直未变的,它还是在很多方面发生了巨大的改变,并取得了巨大的进步.这些改变提高了诸如类型安全,内存管理,性能等方方面面的特性,让编写Objective-C变得更加容易.为了让你现在和未来的代码变得更加健壮,可靠和更加有弹性,适应这些改变将是十分重要的事情. Xcode为你准备了一个适应这些结构化改变的工具.但是在你使用它之前,你会想这些改变会对你的代码做什么改变,并且为什么做这些改变.这篇文档重点讲述了要发生在你的代码

raywenderlich.com Objective-C编码规范

原文链接 : The official raywenderlich.com Objective-C style guide 原文作者 : raywenderlich.com Team 译文出自 : raywenderlich.com Objective-C编码规范 译者 : Sam Lau 由于我正在准备模仿饿了么这个app,到时可能有些iOS开发者参与进来.这时如果每个人的Objective-C编码风格都不一样,这样不易于保持代码一致性和难以Code Review.所以我在网上搜索到 The

iOS 注释的5要3不要和编码规范的26个方面

注释 代码注释,可以说是比代码本身更重要.这里有一些方法可以确保你写在代码中的注释是友好的: 不要重复阅读者已经知道的内容 能明确说明代码是做什么的注释对我们是没有帮助的. // If the color is red, turn it green if (color.is_red()) { color.turn_green(); }   要注释说明推理和历史 如果代码中的业务逻辑以后可能需要更新或更改,那就应该留下注释:) /* The API currently returns an arr

iOS编码规范(简版)

1. 总体指导原则 [规则1-1]首先是为人编写程序,其次才是计算机. 说明:这是软件开发的基本要点,软件的生命周期贯穿产品的开发.测试.生产.用户使用.版本升级和后期维护等长期过程,只有易读.易维护的软件代码才具有生命力,所以提倡写代码之前多思考,特别是逻辑复杂或者技术难点较高的地方,个人思考不清楚的,可以和团队成员进行沟通. [规则1-2]保持代码的简明清晰,避免过分的编程技巧. 说明:简单是最美.保持代码的简单化是软件工程化的基本要求.不要过分追求技巧,否则会降低程序的可读性. [规则1-

ios 8 适配须知

iOS 8.0本文总结了关键developer-related特性介绍了iOS 8,目前航运iOS设备上运行. 本文还列出了文档更详细地描述新功能. 关于已知问题的最新新闻和信息,明白了 iOS 8版本说明 . 新api的完整列表添加在iOS 8中,明白了 iOS 8.0 API差别 . 有关新设备的更多信息,请参阅 iOS设备兼容性参考 . 应用程序扩展iOS 8允许您扩展系统通过提供一个的选择区域 应用程序扩展 代码,支持自定义功能,用户任务的上下文中. 例如,您可能提供一个应用程序扩展,帮