美文网首页
OC底层原理之-isa结构体探索

OC底层原理之-isa结构体探索

作者: SurpleXie | 来源:发表于2020-09-14 16:26 被阅读0次

在分析isa结构体之前,我们应该先思考一下\color{red}{对象的本质}是什么?
首先,我们需要利用Clang来编译OC,Clang编译使用在这篇文章中介绍了

1.对象本质的探究

建立工程,在maim.m中创建一个XpPerson类

@interface XpPerson : NSObject {
    NSString *nickName;
}
@property (nonatomic, copy) NSString *name;
@end

@implementation XpPerson
@end
int main(int argc, char * argv[]) {
    NSString * appDelegateClassName;
    @autoreleasepool {
        // Setup code that might create autoreleased objects goes here.
        appDelegateClassName = NSStringFromClass([AppDelegate class]);
         XpPerson *objc = [XpPerson alloc];
    }
    return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}

通过Clang编译main.cpp文件,我们可以看到XpPerson类


main.cpp文件.jpg
  • 根据上图,我们可以明显看得出XpPerson类类对象在底层中被编译成了一个\color{red}{struct}结构体
extern "C" unsigned long OBJC_IVAR_$_XpPerson$_name;
struct XpPerson_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    NSString *__strong nickName;
    NSString *__strong _name;
};
  • 因为在C++中结构体是可以继承的,\color{red}{XpPerson_IMPL}中的第一个属性其实就是 isa,是继承自NSObject,属于伪继承,伪继承的方式是直接将NSObject结构体定义为\color{red}{XpPerson}中的第一个属性,意味着\color{red}{XpPerson}拥有 NSObject中的所有成员变量。
  • 对象的属性name方法,在OC中会自动带有\color{red}{setter}\color{red}{getter}方法在底层通过objc_setProperty实现
static NSString * _I_XpPerson_name(XpPerson * self, SEL _cmd) { return (*(NSString *__strong *)((char *)self + OBJC_IVAR_$_XpPerson$_name)); }
static void _I_XpPerson_setName_(XpPerson * self, SEL _cmd, NSString *name) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct XpPerson, _name), (id)name, 0, 1); }

总结

  • \color{red}{OC对象的本质 }就是\color{red}{struct结构体 }
  • \color{red}{XpPerson }中的\color{red}{ isa}就是继承自\color{red}{NSObject }中的\color{red}{ isa}
1.对objc_setProperty的探究

底层runtime通过objc_setProperty设置对象属性的sette和getter方法,下载objc4_781源码搜索objc_setProperty


搜索objc_setProperty.jpg

找到objc_setProperty方法,我们可以看到其通过reallySetProperty方法实现,再点击reallySetProperty进去

static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
    if (offset == 0) {
        object_setClass(self, newValue);
        return;
    }

    id oldValue;
    id *slot = (id*) ((char*)self + offset);

    if (copy) {
        newValue = [newValue copyWithZone:nil];
    } else if (mutableCopy) {
        newValue = [newValue mutableCopyWithZone:nil];
    } else {
        if (*slot == newValue) return;
        newValue = objc_retain(newValue);
    }

    if (!atomic) {
        oldValue = *slot;
        *slot = newValue;
    } else {
        spinlock_t& slotlock = PropertyLocks[slot];
        slotlock.lock();
        oldValue = *slot;
        *slot = newValue;        
        slotlock.unlock();
    }

    objc_release(oldValue);
}

通过查看objc_setProperty方法的实现,发现上层属性的set方法到底层的set方法经过objc_setProperty方法处理之后,已经失去了痕迹,只是带进来了每个set方法特有的_cmd,可想而知,objc_setProperty就是上层set和下层set的一个中间关联层

  • objc_setProperty 是关联上层set和下层set的一个中间接口
  • 基于上述原因,苹果采用了适配器设计模式(即将底层接口适配为客户端需要的接口),对外提供一个接口,供上层的set方法使用,对内调用底层的set方法,使其相互不受影响,即无论上层怎么变,下层都是不变的,或者下层的变化也无法影响上层,主要是达到上下层接口隔离的目的


    01.jpg
3.isa
  • nonpointer 情况:isa_t newisa(0);
  • !nonpointer情况: isa = isa_t((uintptr_t)cls);
inline void objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) 
{ 
    ASSERT(!isTaggedPointer()); 
    
    if (!nonpointer) {
        isa = isa_t((uintptr_t)cls);
    } else {
        ASSERT(!DisableNonpointerIsa);
        ASSERT(!cls->instancesRequireRawIsa());

        isa_t newisa(0);//初始化

#if SUPPORT_INDEXED_ISA
        ASSERT(cls->classArrayIndex() > 0);
        newisa.bits = ISA_INDEX_MAGIC_VALUE;
        // isa.magic is part of ISA_MAGIC_VALUE
        // isa.nonpointer is part of ISA_MAGIC_VALUE
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.indexcls = (uintptr_t)cls->classArrayIndex();
#else
        newisa.bits = ISA_MAGIC_VALUE;
        // isa.magic is part of ISA_MAGIC_VALUE
        // isa.nonpointer is part of ISA_MAGIC_VALUE
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.shiftcls = (uintptr_t)cls >> 3;
#endif

        // This write must be performed in a single store in some cases
        // (for example when realizing a class because other threads
        // may simultaneously try to use the class).
        // fixme use atomics here to guarantee single-store and to
        // guarantee memory order w.r.t. the class index table
        // ...but not too atomic because we don't want to hurt instantiation
        isa = newisa;
    }
}

在源码查看isa_t结构体,我们也可以知道其实isa_t中的 cls 和 bits 其实是互斥的。当我们的类型是nonpointer时,bits会有值,当不是nonpointer时,会直接返回cls

union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};

相关文章

网友评论

      本文标题:OC底层原理之-isa结构体探索

      本文链接:https://www.haomeiwen.com/subject/iilpektx.html