我想知道为什么id
是弱引用指针,它是如何处理任何class
类型指针的,并且在运行时我们如何检测分配了哪种类型的类指针id
。
答案 0 :(得分:17)
为什么id是弱引用指针?
id
不是弱引用指针,至少不是ARC所有权意义上的指针。对象的id
类型引用是否弱是取决于已声明__weak
(和变体)的引用,而对象的类实际上支持弱引用。
但是,你可以说id
提供弱类型,虽然我认为动态/鸭子类型是更准确的描述。由于id
类型的引用不包含编译时类类型信息,因此编译器无法确定底层对象是否可以响应给定的选择器,这可能导致运行时错误。
如何处理任何类类型指针?
这是the Objective-C language定义的一部分。编译器将id
识别为每个Objective-C类的超类型,并以不同方式处理id
。请参阅下面的答案。
在运行时,我们如何检测哪个类指针被分配给id?
在Apple的Objective-C运行时,分配给对象的内存中的第一个字节必须指向该对象的类。您可能会在其他地方将此引用为isa
指针,这就是Apple的运行时查找每个 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 Tagged pointers是这种结构的显着偏差,并且(部分)因为它们不应该直接访问isa
指针。
答案 1 :(得分:8)
拥有通用对象类型很好,因此您可以定义可以包含任何类型对象的集合类型,以及可以在不知道对象类型的情况下使用任何对象的其他通用服务。
没有诀窍让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
。这取决于您是想要完全匹配还是包含子类。
答案 2 :(得分:3)
查看头文件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, ...);