id, NSObject *, id<NSObject>区别

  我们经常会混淆以下三种申明:
  1. id foo1;
  2. NSObject *foo2;
  3. id<NSObject> foo3;

  第一种是最常用的,它简单地申明了指向对象的指针,没有给编译器任何类型信息,因此,编译器不会做类型检查。但也因为是这样,你可以发送任何信息给id类型
的对象。这就是为什么+alloc返回id类型,但调用[[Foo alloc] init]不会产生编译错误。

  因此,id类型是运行时的动态类型,编译器无法知道它的真实类型,即使你发送一个id类型没有的方法,也不会产生编译警告。

  我们知道,id类型是一个Objective-C对象,但并不是都指向继承自NSOjbect的对象,即使这个类型和NSObject对象有很多共同的方
法,像retain和release。要让编译器知道这个类继承自NSObject,一种解决办法就是像第2种那样,使用NSObject静态类型,当你
发送NSObject没有的方法,像length或者count时,编译器就会给出警告。这也意味着,你可以安全地使用像
retain,release,description这些方法。

  因此,申明一个通用的NSObject对象指针和你在其它语言里做的类似,像java,但其它语言有一定的限制,没有像Objective-C这样灵活。并
不是所有的Foundation/Cocoa对象都继承息NSObject,比如NSProxy就不从NSObject继承,所以你无法使用
NSObject*指向这个对象,即使NSProxy对象有release和retain这样的通用方法。为了解决这个问题,这时候,你就需要一个指向拥
有NSObject方法对象的指针,这就是第3种申明的使用情景。

  id<NSObject>
告诉编译器,你不关心对象是什么类型,但它必须遵守NSObject协议(protocol),编译器就能保证所有赋值给
id<NSObject>类型的对象都遵守NSObject协议(protocol)。这样的指针可以指向任何NSObject对象,因为
NSObject对象遵守NSObject协议(protocol),而且,它也可以用来保存NSProxy对象,因为它也遵守NSObject协议
(protocol)。这是非常强大,方便且灵活,你不用关心对象是什么类型,而只关心它实现了哪些方法。

  现在你知道你要用什么类型了不?

  如果你不需要任何的类型检查,使用id,它经常作为返回类型,也经常用于申明代理(delegate)类型。因为代理类型通常在运行时,才会检查是否实现了那些方法。

  如果真的需要编译器检查,那你就考虑使用第2种或者第3种。很少看到NSObject*能正常运行,但id<NSObject>无法正常运行
的。使用协议(protocol)的优点是,它能指向NSProxy对象,而更常用的情况是,你只想知道某个对象遵守了哪个协议,而不用关心它是什么类型。

PS:

  id 还可以表示基础类型,但是不能表示float,double类型
  NSObject *foo2; 如果使用这种形式,用到的时候需要强制类型转换,可能会很麻烦

转自:http://www.cocoachina.com/bbs/read.php?tid=151376

时间: 2024-10-13 19:28:42

id, NSObject *, id<NSObject>区别的相关文章

IOS_OC_id ,NSObject, id&lt;NSObject&gt;区别

我们经常会混淆以下三种申明(我是没有留意过): 1. id foo1; 2. NSObject *foo2; 3. id<NSObject> foo3; 第一种是最常用的,它简单地申明了指向对象的指针,没有给编译器任何类型信息,因此,编译器不会做类型检查.但也因为是这样,你可以发送任何信息给id类型的对象.这就是为什么+alloc返回id类型,但调用[[Foo alloc] init]不会产生编译错误. 因此,id类型是运行时的动态类型,编译器无法知道它的真实类型,即使你发送一个id类型没有的

IOS_OC_id ,NSObject, id&amp;lt;NSObject&amp;gt;差别

我们常常会混淆下面三种申明(我是没有留意过): 1. id foo1; 2. NSObject *foo2; 3. id<NSObject> foo3; 第一种是最经常使用的,它简单地申明了指向对象的指针,没有给编译器不论什么类型信息,因此,编译器不会做类型检查.但也由于是这样,你能够发送不论什么信息给id类型的对象.这就是为什么+alloc返回id类型,但调用[[Foo alloc] init]不会产生编译错误. 因此,id类型是执行时的动态类型,编译器无法知道它的真实类型,即使你发送一个i

id 和 instancetype 的区别

1.什么是 instancetype?同 id 一样,都是表示未知类型的对象. 2.关联返回类型的方法根据 Cocoa 规则, 满足下列规则的方法:1.类方法中,以 alloc 或 new 开头.2.实例方法中,以 autorelease,init,retain或 self 开头的这些方法,会返回一个所在类类型的对象,这些方法就被称为是关联返回类型的方法.以代码为例:@interface NSObject+ (id)alloc;- (id)init;@end @interface NSArray

$arr[&#39;id&#39;],$arr[id]的区别

说白了区别就是当不加''的时候我们首先会考虑的是这个id是不是一个常量 例如: define("abc",'ABC'); 那么实际上$arr[id] = $arr['ABC']; 所以在这个过程中就会多加了一步操作.那么引申一个问题就是 在$arr取值时尽量使用单引号就会比直接写或者加双引号就会更快一些. $arr['id'],$arr[id]的区别

android:id=&quot;@android:id/tabhost&quot; 、android:id=&quot;@+id/llRoot&quot; 、android:id=&quot;@id/llRoot&quot; 之间的区别

由于快要放暑假了,所以最近这俩周把Android方面的知识复习一下,准备找个实习工作. 顺便把自己的总结更大家分享一下,共同进步,谢谢.... 一. android:id="@android:id/tabhost"   是调用系统内部的ID 和代码中 mTabContent = (FrameLayout) findViewById(com.android.internal.R.id.tabcontent); 是一回事. 二. android:id="@+id/llRoot&q

在表单(input)中id和name的区别

在表单(input)中id和name的区别  但是name在以下用途是不能替代的: 1. 表单(form)的控件名,提交的数据都用控件的name而不是id来控制.因为有许多name会同时对应多个控件,比如checkbox和radio,而id必须是全文档中唯一的.此外浏览器会根据name来设定发送到服务器的request.因此如果用id,服务器是无法得到数据的. 2. frame和window的名字,用于在其他frame或window指定target. 例如:<frameset cols="

html元素中id和name的区别

可以说几乎每个做过Web开发的人都问过,到底元素的ID和Name有什么区别阿?为什么有了ID还要有Name呢?! 而同样我们也可以得到最classical的答案:ID就像是一个人的身份证号码,而Name就像是他的名字,ID显然是唯一的,而Name是可以重复的. 上周我也遇到了ID和Name的问题,在页面里输入了一个input type="hidden",只写了一个ID='SliceInfo',赋值后submit,在后台用Request.Params["SliceInfo&qu

input 的id 和name什么区别

在表单(input)中id和name的区别 但是name在以下用途是不能替代的: 1. 表单(form)的控件名,提交的数据都用控件的name而不是id来控制.因为有许多name会同时对应多个控件,比如checkbox和radio, 而id必须是全文档中唯一的.此外浏览器会根据name来设定发送到服务器的request.因此如果用id,服务器是无法得到数据的. 2. frame和window的名字,用于在其他frame或window指定target. 以下两者可以通用,但是强烈建议用id不要用n

Android中@id与@+id区别

近日升级adt21+后,在输出apk时碰到编译layout异常,看了下是因为有人在layout引用一个不存在的resID时用了 @+id/xxx,而不是@id/xxx,导致debug编译器没显示错误,而在打包时的编译器出现错误,adt21-则没有此问题. 附上配图说明: Android中@id与@+id区别 : Android中的组件需要用一个int类型的值来表示,这个值也就是组件标签中的id属性值. id属性只能接受资源类型的值,也就是必须以@开头的值,例如,@id/abc.@+id/xyz等

ID,ClientID,UniqueID的区别

ID是设计的时候所指定的ID. ClientID是当这个控件生成到客户端页面时候,需要在客户端访问时候用的. UniqueID是当需要参与服务端回传的时候用的. 备注:当控件是子控件的时候(例如在用户控件中的Button),ClientID在HTML页面中是作为控件的ID属性,UniqueID是作为控件的Name属性,如果不是子控件,那么ClientID和UniqueID是相同的 例如: MyControl1是一个用户控件,里面包含一个ID为Button1的按钮,把MyControl1放在一个页