美文网首页
OC 源码笔记

OC 源码笔记

作者: 10m每秒滑行 | 来源:发表于2019-04-17 18:58 被阅读0次
    1. 为什么说NSObject 的 isa 指针指向class对象
      源码getclass的实现如下
    Class object_getClass(id obj)
    {
        if (obj) return obj->getIsa();
        else return Nil;
    }
    

    OC 的 Class 对象 是 objc_class 结构体的指针
    typedef struct objc_class *Class;

    1. 有人说Class 对象 isa 指针指向 meta class,meta class 的 isa 指针指向 superClass
      objc_class 结构体定义如下,以及getMeta 的实现:
    struct objc_class : objc_object {
        // Class ISA;
        Class superclass;
          cache_t cache; // 类的方法缓存表
        class_data_bits_t bits; // 记录类的属性,方法,protocol,以及一系列标识位
        ...
        Class getMeta() {
            if (isMetaClass()) return (Class)this;
            else return this->ISA();
        }
    
        ...
    }
    

    此说法并不完全准确,在objc-runtime 源码中 objc_object 通过isa指针访问类对象, objc_class 通过 superclass 指针 来访问父类的 class 对象,因为 objc_class 继承自 objc_object,理论上也是一个 object,所以,class 会有 isMetaClass 方法的判断,通过获取 bits 中的标识位,来返回是否是 metaClass 如果是,则是类对象,返回自己,否则视为object 对象,调用 objc_object 的 ISA() 方法 获取metaClass,meta class 是名称的指代,是个方法

    1. 关于方法实现的查找和转发过程, objc-runtime 中的实现细节
    IMP lookUpImpOrForward(Class cls, SEL sel, id inst, 
                           bool initialize, bool cache, bool resolver)
    {
        Class curClass;
        IMP methodPC = nil;
        Method meth;
         //缓存查找
        if (cache) {
            methodPC = _cache_getImp(cls, sel);
            if (methodPC) return methodPC;    
        }
    
        // freed class 查找
        if (cls == _class_getFreedObjectClass())
            return (IMP) _freedHandler;
    
        //类的方法列表中查找
        {
            Method meth = getMethodNoSuper_nolock(cls, sel);
            if (meth) {
                log_and_fill_cache(cls, meth->imp, sel, inst, cls);
                imp = meth->imp;
                goto done;
            }
        }
    
        // 父类的cache和方法列表查找
                {
            unsigned attempts = unreasonableClassCount();
            for (Class curClass = cls->superclass;
                 curClass != nil;
                 curClass = curClass->superclass)
            {
                // Halt if there is a cycle in the superclass chain.
                if (--attempts == 0) {
                    _objc_fatal("Memory corruption in class list.");
                }
                
                // Superclass cache.
                imp = cache_getImp(curClass, sel);
                if (imp) {
                    if (imp != (IMP)_objc_msgForward_impcache) {
                        log_and_fill_cache(cls, imp, sel, inst, curClass);
                        goto done;
                    }
                    else {
                        break;
                    }
                }
                
                // Superclass method list.
                Method meth = getMethodNoSuper_nolock(curClass, sel);
                if (meth) {
                    log_and_fill_cache(cls, meth->imp, sel, inst, curClass);
                    imp = meth->imp;
                    goto done;
                }
            }
        }
        // 未找到方法的实现,没有找到的话,尝试做消息转发 
            if (resolver  &&  !triedResolver) {
            runtimeLock.unlockRead();
            _class_resolveMethod(cls, sel, inst);
            runtimeLock.read();
            triedResolver = YES;
            goto retry;
        }
       // 获取转发的 imp
        imp = (IMP)_objc_msgForward_impcache;
        cache_fill(cls, sel, imp, inst);
    
     done:
        runtimeLock.unlockRead();
        return imp;
    }
    
    1. 用人总结 load 和 initialize 方法的区别时提到
      load 是类加载到内存时候调用, 优先父类->子类->分类
      initialize 是类第一次收到消息时候调用,优先分类->子类->父类

    写代码验证 load 方法 在main 函数执行之前 无论是否使用到这个类,load 函数一定会被调用,无论是否有子类,子类是否也实现了 load 方法,load 方法都会被调用,并且 优先父类->子类->分类,

    但是 initialize 是在 main 函数之后调用,同样,调用时机在 objc-runtim 中可以找到,当动态运行时,一旦要访问 一个创建一个类的对象object(初始化对object 需要使用 class 的一系列信息),或者访问 class 的属性,class 的方法,只要涉及到要访问 class 信息时,都会先检查 meta class 是否被初始化 如果没有,则会先调用 类的 initialize 方法,所以什么时候调用 initialize,由代码决定,如果用到了class 就会调用 initialize,没用到,则不会被调用,并不是 classA 继承 classB , classA 的 initialize 一定会比 classB 的 initialize 方法先调用,而是根据代码编写的时候,先触发了哪个类的访问来决定。写代码验证也确实可以有 父类的 initialize 比子类先调用的情况.当一个类有N个子类的时候,任何一个子类的创建,都有可能出发c触发父类的initialize被调用,但其他子类的 initialize 却没有被调用。

    1. Copy 调用的是copyWithZone
    - (id)copy
    {
        return [self copyFromZone: [self zone]];
    }
    
    1. isKindOfClass 和 isMemberOfClass 区别
      isKindOfClass 会对比父类 class
    - (BOOL)isKindOf:aClass
    {//会对比父类
        Class cls;
        for (cls = isa; cls; cls = cls->superclass) 
            if (cls == (Class)aClass)
                return YES;
        return NO;
    }
    
    - (BOOL)isMemberOf:aClass
    {
        return isa == (Class)aClass;
    }
    
    1. strong 类型property 实现
    void
    objc_storeStrong(id *location, id obj)
    {
        id prev = *location;
        if (obj == prev) {
            return;
        }
        objc_retain(obj);
        *location = obj;
        objc_release(prev);
    }
    
    1. weak 类型property 实现
      放在weakHashTable 里了, set的时候 不会 retain,get的时候会 retain
    void _object_setIvar(id obj, Ivar ivar, id value, bool assumeStrong)
    {
        if (!obj  ||  !ivar  ||  obj->isTaggedPointer()) return;
    
        ptrdiff_t offset;
        objc_ivar_memory_management_t memoryManagement;
        _class_lookUpIvar(obj->ISA(), ivar, offset, memoryManagement);
    
        if (memoryManagement == objc_ivar_memoryUnknown) {
            if (assumeStrong) memoryManagement = objc_ivar_memoryStrong;
            else memoryManagement = objc_ivar_memoryUnretained;
        }
    
        id *location = (id *)((char *)obj + offset);
    
        switch (memoryManagement) {
        case objc_ivar_memoryWeak:       objc_storeWeak(location, value); break;
        case objc_ivar_memoryStrong:     objc_storeStrong(location, value); break;
        case objc_ivar_memoryUnretained: *location = value; break;
        case objc_ivar_memoryUnknown:    _objc_fatal(“impossible”);
        }
    }
    

    默认 assumeStrong 为no, 不是strong的话,走的是 unsafe_unretain

    1. property 的Atomic 实现加 os_unfair_lock ,atomic 能保证,多线程读写属性是安全的 , 除了读写加锁之外,在 getproperty的实现中 调用了 objc_retain ,保证 返回的对象,不会被立即释放,这也是,atomic 属性 保证读写操作安全的关键
    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);
    }
    
    id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
        if (offset == 0) {
            return object_getClass(self);
        }
    
        // Retain release world
        id *slot = (id*) ((char*)self + offset);
        if (!atomic) return *slot;
            
        // Atomic retain release world
        spinlock_t& slotlock = PropertyLocks[slot];
        slotlock.lock();
        id value = objc_retain(*slot);
        slotlock.unlock();
        
        // for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
        return objc_autoreleaseReturnValue(value);
    }
    
    1. AssociationsManager 管理动态运行时 绑定 是个全局变量
    void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
        // retain the new value (if any) outside the lock.
        ObjcAssociation old_association(0, nil);
        id new_value = value ? acquireValue(value, policy) : nil;
        {
            AssociationsManager manager;
            AssociationsHashMap &associations(manager.associations());
            disguised_ptr_t disguised_object = DISGUISE(object);
            if (new_value) {
                // break any existing association.
                AssociationsHashMap::iterator I = associations.find(disguised_object);
                if (I != associations.end()) {
                    // secondary table exists
                    ObjectAssociationMap *refs = I->second;
                    ObjectAssociationMap::iterator j = refs->find(key);
                    if (j != refs->end()) {
                        old_association = j->second;
                        j->second = ObjcAssociation(policy, new_value);
                    } else {
                        (*refs)[key] = ObjcAssociation(policy, new_value);
                    }
                } else {
                    // create the new association (first time).
                    ObjectAssociationMap *refs = new ObjectAssociationMap;
                    associations[disguised_object] = refs;
                    (*refs)[key] = ObjcAssociation(policy, new_value);
                    object->setHasAssociatedObjects();
                }
            } else {
                // setting the association to nil breaks the association.
                AssociationsHashMap::iterator I = associations.find(disguised_object);
                if (I !=  associations.end()) {
                    ObjectAssociationMap *refs = I->second;
                    ObjectAssociationMap::iterator j = refs->find(key);
                    if (j != refs->end()) {
                        old_association = j->second;
                        refs->erase(j);
                    }
                }
            }
        }
        // release the old value (outside of the lock).
        if (old_association.hasValue()) ReleaseValue()(old_association);
    }
    

    相关文章

      网友评论

          本文标题:OC 源码笔记

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