我想知道为什么id
是一个弱引用指针,它如何能够处理任何class
类型的指针,以及在运行时我们如何检测哪种类型的类指针被分配给id
为什么id是弱引用指针?
id
不是一个弱引用指针,至少在ARC所有权意义上不是。一个对象的id
类型的引用是否弱,取决于该引用被声明为__weak
(及其变体),以及该对象的类实际上支持弱引用。
id
提供了弱类型,尽管我认为动态/duck类型是更准确的描述。由于id
类型的引用不包含编译时的类类型信息,例如,编译器无法确定底层对象是否可以响应给定的选择器,这可能导致运行时错误。
它如何能够处理任何类类型指针?
这是Objective-C语言定义的一部分。编译器将id
识别为每个Objective-C类的超类型,并以不同的方式对待id
。请看下面的答案。
在Apple的Objective-C运行时中,分配给对象的内存中的第一个字节必须指向该对象的类。你可能会在其他地方看到这个引用作为在运行时,我们如何检测哪种类型的类指针被分配给id?
isa
指针,这就是苹果的运行时如何找出每个1对象的类。id
类型也被定义为具有这些信息。事实上,它唯一的属性是isa
指针,这意味着所有1 Objective-C对象都符合这个定义。
如果你有一个id
引用,想要发现被引用对象的类,你可以发送-class
:
id someObject;
// Assign something to someObject
// Log the corresponding class
Class c = [someObject class];
NSLog(@"class = %@", c);
// Test whether the object is of type NSString (or a subclass of NSString)
if ([someObject isKindOfClass:[NSString class]]) {
NSLog(@"it's a string");
}
1标记指针是这种结构的一个明显偏差,并且(部分)因为它们不应该直接访问isa
指针
有一个泛型对象类型是很好的,这样你就可以定义可以容纳任何类型对象的集合类型,以及其他可以处理任何对象的泛型服务,而不需要知道它是什么类型的对象。
没有任何技巧可以使id工作。在二进制级别,所有指针都是可互换的。它们只是将内存地址表示为一个数值。要使id接受任何类型的指针,只需要禁用编译器中通常要求指针类型匹配的规则。
你可以通过以下几种方式找到关于id类型变量的类的信息:
id theObject = // ... something
Class theClass = [theObject class];
NSString *className = NSStringFromClass(theClass);
NSClassDescription *classDescription = [NSClassDescription classDescriptionForClass:theClass];
但是在代码中很少需要做这些事情。更常见的情况是,您希望测试id变量是否是特定类的实例,如果是,则将其强制转换为该类并开始将其视为该类型。
if ([theObject isKindOfClass:[MySpecializedClass class]]) {
MySpecializedClass *specialObject = (MySpecializedClass *)theObject;
[specialObject doSomethingSpecial];
}
如果您要使用-class
来查找类,但它返回的是一个您一无所知的类,那么无论如何您都无法对基于其类的对象做任何特殊操作。因此,除了检查它是否与您所知道的类匹配之外,没有理由做任何事情,并且只有在您打算对这些类进行特殊处理时才会这样做。
有时可以使用isMemberOfClass
代替isKindOfClass
。
也许值得看看头文件objc/objc.h来查找id
的内部信息。
typedef struct objc_class *Class;
typedef struct objc_object {
Class isa;
} *id;
typedef struct objc_selector *SEL;
typedef id (*IMP)(id, SEL, ...);