为什么id是泛型指针



我想知道为什么id是一个弱引用指针,它如何能够处理任何class类型的指针,以及在运行时我们如何检测哪种类型的类指针被分配给id

为什么id是弱引用指针?

id不是一个弱引用指针,至少在ARC所有权意义上不是。一个对象的id类型的引用是否弱,取决于该引用被声明为__weak(及其变体),以及该对象的类实际上支持弱引用。

然而,您可以说id提供了弱类型,尽管我认为动态/duck类型是更准确的描述。由于id类型的引用不包含编译时的类类型信息,例如,编译器无法确定底层对象是否可以响应给定的选择器,这可能导致运行时错误。

它如何能够处理任何类类型指针?

这是Objective-C语言定义的一部分。编译器将id识别为每个Objective-C类的超类型,并以不同的方式对待id。请看下面的答案。

在运行时,我们如何检测哪种类型的类指针被分配给id?

在Apple的Objective-C运行时中,分配给对象的内存中的第一个字节必须指向该对象的类。你可能会在其他地方看到这个引用作为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, ...); 

最新更新