返回

isKindOfClass的源码坑

IOS

iOS底层实验室

在iOS开发中,isKindOfClass方法是用来判断一个对象是否属于某个类的实例。它经常被用于类型检查和类型转换。然而,如果开发者不熟悉ISAClass等底层概念,那么在使用isKindOfClass时很容易踩坑。

本篇文章将深入探讨isKindOfClass的源码,揭示隐藏的坑点,并提供避免这些坑点的建议。

isKindOfClass的源码

isKindOfClass方法的源码位于objc/runtime.h头文件中,如下所示:

BOOL isKindOfClass(id obj, Class cls)

其中:

  • obj是要检查的对象。
  • cls是要比较的类。

该方法的实现非常简单:

BOOL isKindOfClass(id obj, Class cls) {
    return obj->isa == cls;
}

从源码可以看出,isKindOfClass通过比较对象的ISA指针和目标类的指针来确定对象是否属于该类。ISA指针指向对象的类对象,它存储了对象的类型信息。

坑点 1:ISA指针的改变

第一个坑点是ISA指针的改变。在某些情况下,对象的ISA指针可能会被改变,导致isKindOfClass的判断结果不准确。例如:

// 创建一个NSObject对象
NSObject *obj = [[NSObject alloc] init];

// 修改对象的ISA指针
object_setClass(obj, [NSString class]);

// 判断对象是否属于NSString类
BOOL isNSString = [obj isKindOfClass:[NSString class]];

在这种情况下,object_setClass函数将objISA指针修改为NSString类的指针。因此,isKindOfClass将返回YES,即使obj实际上是一个NSObject对象。

坑点 2:Class的嵌套

第二个坑点是Class的嵌套。在Objective-C中,类可以嵌套在其他类中。例如:

// 创建一个嵌套类
@interface OuterClass : NSObject
{
    // InnerClass作为OuterClass的一个成员变量
    InnerClass *_innerClass;
}
@end

@interface InnerClass : NSObject
@end

在这种情况下,InnerClass是一个嵌套在OuterClass中的内部类。如果使用isKindOfClass来判断一个InnerClass对象是否属于OuterClass类,则结果将为NO

// 创建一个InnerClass对象
InnerClass *innerClass = [[InnerClass alloc] init];

// 判断对象是否属于OuterClass类
BOOL isOuterClass = [innerClass isKindOfClass:[OuterClass class]];

这是因为InnerClass对象的ISA指针指向InnerClass类,而不是OuterClass类。

避免坑点的建议

为了避免isKindOfClass的坑点,建议开发者遵循以下建议:

  • 谨慎修改ISA指针。 仅在特殊情况下才修改对象的ISA指针。
  • 理解Class的嵌套。 注意类嵌套可能会导致isKindOfClass的判断结果不准确。
  • 使用其他类型检查方法。 如果需要更准确的类型检查,可以考虑使用conformsToProtocolisMemberOfClass方法。