OC中instancetype与id的区别

本文详细介绍了Objective-C中的instancetype关键字,解释了其如何改善类型安全,并通过示例对比了它与id的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Written by Mattt Thompson on Dec 10th, 2012

Objective-C is a rapidly evolving language, in a way that you just don’t see in established programming languages. ARC, object literals, subscripting, blocks: in the span of just three years, so much of how we program in Objective-C has been changed (for the better).

All of this innovation is a result of Apple’s philosophy of vertical integration. Just as Apple’s investment in designing its own chipsets gave them leverage to compete aggressively with their mobile hardware, so too has their investment in LLVM allowed their software to keep pace.

Clang developments range from the mundane to paradigm-changing, but telling the difference takes practice. Because we’re talking about low-level language features, it’s difficult to understand what implications they may have higher up with API design.

One such example is instancetype, the subject of this week’s article.


In Objective-C, conventions aren’t just a matter of coding best-practices, they are implicit instructions to the compiler.

For example, alloc and init both have return types of id, yet in Xcode, the compiler makes all of the correct type checks. How is this possible?

In Cocoa, there is a convention that methods with names like alloc, or init always return objects that are an instance of the receiver class. These methods are said to have a related result type.

Class constructor methods, although they similarly return id, don’t get the same type-checking benefit, because they don’t follow that naming convention.

You can try this out for yourself:

[[[NSArray alloc] init] mediaPlaybackAllowsAirPlay]; // ❗ "No visible @interface for `NSArray` declares the selector `mediaPlaybackAllowsAirPlay`"

[[NSArray array] mediaPlaybackAllowsAirPlay]; // (No error)

Because alloc and init follow the naming convention for being a related result type, the correct type check against NSArray is performed. However, the equivalent class constructor array does not follow that convention, and is interpreted as id.

id is useful for opting-out of type safety, but losing it when you do want it sucks.

The alternative, of explicitly declaring the return type ((NSArray *) in the previous example) is a slight improvement, but is annoying to write, and doesn’t play nicely with subclasses.

This is where the compiler steps in to resolve this timeless edge case to the Objective-C type system:

instancetype is a contextual keyword that can be used as a result type to signal that a method returns a related result type. For example:

@interface Person
+ (instancetype)personWithName:(NSString *)name;
@end

instancetype, unlike id, can only be used as the result type in a method declaration.

With instancetype, the compiler will correctly infer that the result of +personWithName: is an instance of a Person.

Look for class constructors in Foundation to start using instancetype in the near future. New APIs, such as UICollectionViewLayoutAttributes are using instancetype already.

下面的翻译:原文:http://blog.youkuaiyun.com/wzzvictory/article/details/16994913

一、什么是instancetype

instancetype是clang 3.5开始,clang提供的一个关键字,表示某个方法返回的未知类型的Objective-C对象。我们都知道未知类型的的对象可以用id关键字表示,那为什么还会再有一个instancetype呢?

二、关联返回类型(related result types)

根据Cocoa的命名规则,满足下述规则的方法:

1、类方法中,以alloc或new开头

2、实例方法中,以autorelease,init,retain或self开头

会返回一个方法所在类类型的对象,这些方法就被称为是关联返回类型的方法。换句话说,这些方法的返回结果以方法所在的类为类型,说的有点绕口,请看下面的例子:

@interface NSObject  
+ (id)alloc;  
- (id)init;  
@end  
@interface NSArray : NSObject  
@end  

当我们使用如下方式初始化NSArray时:

NSArray *array = [[NSArray alloc] init];  

按照Cocoa的命名规则,语句[NSArray alloc] 的类型就是NSArray*,因为alloc的返回类型属于关联返回类型。同样,[[NSArray alloc]init] 的返回结果也是NSArray*。

三、instancetype作用

1、作用
如果一个不是关联返回类型的方法,如下:

@interface NSArray  
+ (id)constructAnArray;  
@end  

当我们使用如下方式初始化NSArray时:

[NSArray constructAnArray];  

根据Cocoa的方法命名规范,得到的返回类型就和方法声明的返回类型一样,是id。
但是如果使用instancetype作为返回类型,如下:

@interface NSArray  
+ (instancetype)constructAnArray;  
@end  

当使用相同方式初始化NSArray时:

[NSArray constructAnArray];  

得到的返回类型和方法所在类的类型相同,是NSArray*!
总结一下,instancetype的作用,就是使那些非关联返回类型的方法返回所在类的类型!

2、好处
能够确定对象的类型,能够帮助编译器更好的为我们定位代码书写问题,比如:

[[[NSArray alloc] init] mediaPlaybackAllowsAirPlay]; //  "No visible @interface for `NSArray` declares the selector `mediaPlaybackAllowsAirPlay`" 
[[NSArray array] mediaPlaybackAllowsAirPlay]; // (No error)  

上例中第一行代码,由于[[NSArray alloc]init]的结果是NSArray*,这样编译器就能够根据返回的数据类型检测出NSArray是否实现mediaPlaybackAllowsAirPlay方法。有利于开发者在编译阶段发现错误。
第二行代码,由于array不属于关联返回类型方法,[NSArray array]返回的是id类型,编译器不知道id类型的对象是否实现了mediaPlaybackAllowsAirPlay方法,也就不能够替开发者及时发现错误。

四、instancetype和id的异同

1、相同点
都可以作为方法的返回类型

2、不同点
①instancetype可以返回和方法所在类相同类型的对象,id只能返回未知类型的对象;

②instancetype只能作为返回值,不能像id那样作为参数,比如下面的写法:

//err,expected a type  
- (void)setValue:(instancetype)value  
{  
    //do something  
}  

就是错的,应该写成:

- (void)setValue:(id)value  
{  
    //do something  
}  
一、综合实战—使用极轴追踪方式绘制信号灯 实战目标:利用对象捕捉追踪和极轴追踪功能创建信号灯图形 技术要点:结合两种追踪方式实现精确绘图,适用于工程制图中需要精确定位的场景 1. 切换至AutoCAD 操作步骤: 启动AutoCAD 2016软件 打开随书光盘中的素材文件 确认工作空间为"草图注释"模式 2. 绘图设置 1)草图设置对话框 打开方式:通过"工具→绘图设置"菜单命令 功能定位:该对话框包含捕捉、追踪等核心绘图辅助功能设置 2)对象捕捉设置 关键配置: 启用对象捕捉(F3快捷键) 启用对象捕捉追踪(F11快捷键) 勾选端点、中心、圆心、象限点等常用捕捉模式 追踪原理:命令执行时悬停光标可显示追踪矢量,再次悬停可停止追踪 3)极轴追踪设置 参数设置: 启用极轴追踪功能 设置角度增量为45度 确认后退出对话框 3. 绘制信号灯 1)绘制圆形 执行命令:"绘图→圆→圆心、半径"命令 绘制过程: 使用对象捕捉追踪定位矩形中心作为圆心 输入半径值30并按Enter确认 通过象限点捕捉确保圆形位置准确 2)绘制直线 操作要点: 选择"绘图→直线"命令 捕捉矩形上边中点作为起点 捕捉圆的上象限点作为终点 按Enter结束当前直线命令 重复技巧: 按Enter可重复最近使用的直线命令 通过圆心捕捉和极轴追踪绘制放射状直线 最终形成完整的信号灯指示图案 3)完成绘制 验证要点: 检查所有直线是否准确连接圆心和象限点 确认极轴追踪的45度增量是否体现 保存绘图文件(快捷键Ctrl+S)
### OC语言的命名规则格式规范 Objective-C(简称OC)是一门面向对象编程语言,它在C语言的基础上扩展了面向对象的功能。OC语言的命名规则和格式规范对于编写可读性高、易于维护的代码至关重要[^1]。 #### 1. 类名命名规则 类名通常以大写字母开头,并采用**驼峰式命名法**(CamelCase)。例如,`NSString` 或 `UIViewController`。这种命名方式有助于区分类名其他标识符。此外,开发者通常会在自定义类名前加上前缀以避免命名冲突。例如,`MYCustomViewController` 中的 `MY` 是前缀[^2]。 #### 2. 方法命名规则 方法名应清晰描述其功能,通常由多个单词组成,首单词以小写字母开头,后续单词首字母大写。例如,`addObject:` 或 `removeAllObjects`。如果方法包含参数,则参数名应紧随动词之后,形成自然语言风格的方法签名。例如: ```objc - (void)insertObject:(id)object atIndex:(NSUInteger)index; ``` 这种方法签名表示插入一个对象到指定索引位置,参数名增强了代码的可读性[^3]。 #### 3. 变量命名规则 变量名也遵循驼峰式命名法,但首字母小写。例如,`objectCount` 或 `currentPosition`。局部变量和实例变量可以使用类似命名方式,但实例变量通常以下划线 `_` 开头以区别于普通变量。例如,`_name` 或 `_age`[^4]。 #### 4. 常量命名规则 常量通常全部大写,单词之间用下划线 `_` 分隔。例如,`MAX_VALUE` 或 `DEFAULT_TIMEOUT`。这种方式使常量在代码中更加显眼,便于识别[^5]。 #### 5. 枚举类型命名规则 枚举类型的值通常以大写字母开头,并使用前缀标明所属类别。例如,`NSFontTraitMask` 中的 `NS` 表示该枚举属于 Foundation 框架。枚举值则采用全大写形式,如 `UIBarPositionTopAttached`[^6]。 #### 6. 协议命名规则 协议名通常以“ing”结尾,表示某种行为或能力。例如,`NSCopying` 或 `UITableViewDataSource`。这种命名方式直观地表达了协议的功能[^7]。 #### 7. 错误处理命名规则 错误相关的变量或方法通常以 `Error` 结尾。例如,`NSError *error` 或 `handleError:`。这种命名方式明确指出了变量或方法错误处理相关[^8]。 ### 示例代码 以下是一个符合OC命名规范的简单类定义: ```objc @interface MYPerson : NSObject @property (nonatomic, strong) NSString *firstName; @property (nonatomic, strong) NSString *lastName; - (instancetype)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName; - (void)sayHelloWithError:(NSError **)error; @end ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值