美文网首页Kevin的IOS开发专题
【IOS开发高级系列】NSObject专题

【IOS开发高级系列】NSObject专题

作者: Kevin_Junbaozi | 来源:发表于2019-01-14 22:40 被阅读3次

    1 NSObject源码实现分析

    Objective-C NSObject的实现分析(2014-10-23更新)

    http://blog.csdn.net/uxyheaven/article/details/38120335

    1.1 属性

    1.1.1 isa

        是一个指向Class的指针,具体请看这篇文章Objective-C objc_class介绍

    1.2 方法

    1.2.1 class

    实例方法返回的是isa指针, 类方法返回的是本身

    代码实现如下:

    - class 

        return (id)isa;  

    + class  

        return self; 

    }

    1.2.2 superclass

    返回父类

    代码实现如下:

    + superclass  

    {  

        return class_getSuperclass((Class)self);  

    - superclass  

    {  

        return class_getSuperclass(isa);  

    + superclass

    {

        return class_getSuperclass((Class)self);

    }

    - superclass

    {

        return class_getSuperclass(isa);

    }

            调用的是runtime中的class_getSuperclass方法,跟踪到最后实例方法返回的是isa->superclass,类方法返回的是self->superclass

    static class_t * getSuperclass(class_t *cls) 

        if (!cls) return NULL; 

        return cls->superclass; 

    1.2.3 isEqual

    就是直接比较

    - (BOOL)isEqual:anObject 

        return anObject ==self;  

    - (BOOL)isEqual:anObject

    {

        return anObject == self;

    }

    1.2.4 isMemberOf:

    - (BOOL)isMemberOf:aClass

    {

        return isa == (Class)aClass;

    }

            看代码可以得知是通过比较实例对象的isa是否和 传过来的[类 Class] 一样来判断的.而实例对象的isa确实就是指着实例对象的类的.

    - (BOOL)isMemberOf:aClass 

        return isa ==(Class)aClass; 

    }

    1.2.5 isKindOf:

    - (BOOL)isKindOf:aClass

    {

        register Class cls;

        for (cls = isa; cls; cls = class_getSuperclass(cls))

            if (cls == (Class)aClass)

                return YES;

        return NO;

    }

    // class_getSuperclass展开后如下

    static class_t *getSuperclass(class_t *cls)

    {

        if (!cls) return NULL;

        return cls->superclass;

    }

            代码思路也很好理解,如果自己的isa等于aClass(aClass的父类,此处循环)就返回YES,否则返回NO

    - (BOOL)isKindOf:aClass 

        register Classcls; 

        for (cls = isa;cls; cls = class_getSuperclass(cls))  

            if (cls ==(Class)aClass) 

                returnYES; 

        return NO; 

    // class_getSuperclass展开后如下  

    static class_t * getSuperclass(class_t *cls) 

        if (!cls) returnNULL; 

        return cls->superclass; 

    1.2.6 init

    - init

    {

        return self;

    }

    没什么好说的

    - init 

        return self; 

    1.2.7 alloc

    + alloc 

        return (*_zoneAlloc)((Class)self, 0, malloc_default_zone());  

    }

    + alloc

    {

        return (*_zoneAlloc)((Class)self, 0, malloc_default_zone());

    }

        这里有一个函数指针和一个结构体,我们跟进去看

    id (*_zoneAlloc)(Class, size_t, voidvoid *) =_class_createInstanceFromZone; 

    PRIVATE_EXTERN id

    _class_createInstanceFromZone(Class cls, size_t extraBytes,voidvoid *zone)

        id obj; 

        size_t size; 

        // Can't createsomething for nothing  

        if (!cls) returnnil; 

        // Allocate andinitialize  

        size =_class_getInstanceSize(cls) + extraBytes; 

        // CF requires allobjects be at least 16 bytes.  

        if (size < 16)size = 16; 

    #if SUPPORT_GC  

        if (UseGC) { 

            obj =(id)auto_zone_allocate_object(gc_zone, size, AUTO_OBJECT_SCANNED, 0, 1); 

        } else  

    #endif  

        if (zone) { 

            obj = (id)malloc_zone_calloc (zone, 1, size); 

        } else { 

            obj = (id)calloc(1, size); 

        } 

        if (!obj) return nil; 

        obj->isa =cls; 

        if(_class_hasCxxStructors(cls)) { 

            obj =_objc_constructOrFree(cls, obj); 

        } 

        return obj; 

    id (*_zoneAlloc)(Class, size_t, void *) = _class_createInstanceFromZone;

    PRIVATE_EXTERN id

    _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone)

    {

        id obj;

        size_t size;

        // Can't create something for nothing

        if (!cls) return nil;

        // Allocate and initialize

        size = _class_getInstanceSize(cls) + extraBytes;

        // CF requires all objects be at least 16 bytes.

        if (size < 16) size = 16;

    #if SUPPORT_GC

        if (UseGC) {

            obj = (id)auto_zone_allocate_object(gc_zone, size, AUTO_OBJECT_SCANNED, 0, 1);

        } else

    #endif

        if (zone) {

            obj = (id)malloc_zone_calloc (zone, 1, size);

        } else {

            obj = (id)calloc(1, size);

        }

        if (!obj) return nil;

        obj->isa = cls;

        if (_class_hasCxxStructors(cls)) {

            obj = _objc_constructOrFree(cls, obj);

        }

        return obj;

    }

        上面那段代码的作用是:

        1、得到这个类占用多少空间,最小占16 bytes;

        2、然后就给这个实例分配多少空间, 如果失败的话就返回nil;

        3、把这个实例的isa设置成这个类对象;

        4、如果cls的info设置了get属性就用cls这个类在obj这个空间去构造一个实例,跟进去是

    static BOOL object_cxxConstructFromClass(id obj, Class cls)

    {

        id (*ctor)(id);

        Class supercls;

        // Stop if neither this class nor any superclass has ctors.

        if (!_class_hasCxxStructors(cls)) return YES;  // no ctor - ok

        supercls = _class_getSuperclass(cls);

        // Call superclasses' ctors first, if any.

        if (supercls) {

            BOOL ok = object_cxxConstructFromClass(obj, supercls);

            if (!ok) return NO;  // some superclass's ctor failed - give up

        }

        // Find this class's ctor, if any.

        ctor = (id(*)(id))lookupMethodInClassAndLoadCache(cls, SEL_cxx_construct);

        if (ctor == (id(*)(id))&_objc_msgForward_internal) return YES;  // no ctor - ok

        // Call this class's ctor.

        if (PrintCxxCtors) {

            _objc_inform("CXX: calling C++ constructors for class %s", _class_getName(cls));

        }

        if ((*ctor)(obj)) return YES;  // ctor called and succeeded - ok

        // This class's ctor was called and failed.

        // Call superclasses's dtors to clean up.

        if (supercls) object_cxxDestructFromClass(obj, supercls);

        return NO;

    }

        大意是,先看自己有没有父类,有就递归调用自己,然后给自己添加方法,然后添加类别

    1.2.8 new

    + new

    {

        id newObject =(*_alloc)((Class)self, 0);

        Class metaClass =self->isa;

        if(class_getVersion(metaClass) > 1)

            return[newObject init];

        else

            returnnewObject;

    }

    跟进去看一下,发现是和alloc差不多

    id (*_alloc)(Class, size_t) = _class_createInstance; 

    static id _class_createInstance(Class cls, size_textraBytes) 

        return_class_createInstanceFromZone (cls, extraBytes, NULL); 

    1.2.9 free

    - free  

    {  

        return(*_dealloc)(self);  

    + free 

        return nil;  

    跟进去看一下

    static id _object_dispose(idanObject)  

        if (anObject==nil)return nil; 

       objc_destructInstance(anObject); 

    #if SUPPORT_GC  

        if (UseGC) { 

           auto_zone_retain(gc_zone, anObject); // gc free expects rc==1  

        } else  

    #endif  

        { 

            // onlyclobber isa for non-gc  

           anObject->isa = _objc_getFreedObjectClass ();  

        } 

       free(anObject); 

        return nil; 

    void *objc_destructInstance(id obj)  

        if (obj) { 

            Class isa =_object_getClass(obj); 

            if(_class_hasCxxStructors(isa)) { 

               object_cxxDestruct(obj); 

            } 

            if(_class_instancesHaveAssociatedObjects(isa)) { 

               _object_remove_assocations(obj); 

            } 

            if (!UseGC) objc_clear_deallocating(obj); 

        } 

        return obj; 

        1、执行一个叫object_cxxDestruct的东西干了点什么事(沿着继承链逐层向上搜寻SEL_cxx_destruct这个selector,找到函数实现(void (*)(id)(函数指针)并执行);

        2、 执行_object_remove_assocations去除和这个对象关联的对象;

        3、执行objc_clear_deallocating,清空引用计数表并清除弱引用表,将所有weak引用指nil

    1.2.10 respondsTo:

        是查找有没有实现某个方法

    - (BOOL)respondsTo:(SEL)aSelector  

        return class_respondsToMethod(isa, aSelector); 

    BOOL class_respondsToMethod(Class cls, SEL sel) 

       OBJC_WARN_DEPRECATED; 

        return class_respondsToSelector(cls, sel); 

    BOOL class_respondsToSelector(Class cls, SEL sel) 

        IMP imp; 

        if (!sel  || !cls) return NO; 

        // Avoids+initialize because it historically did so.  

        // We're notreturning a callable IMP anyway.  

        imp = lookUpMethod(cls, sel, NO/*initialize*/, YES/*cache*/); 

        return (imp != (IMP)_objc_msgForward_internal)? YES : NO; 

    1.2.11 perform:

    perform是发送消息到指定的接收器并返回值,下面是代码:

    - perform:(SEL)aSelector  

    {  

        if(aSelector) 

            returnobjc_msgSend(self, aSelector);  

        else 

            return [selferror:_errBadSel, sel_getName(_cmd), aSelector]; 

            原来就是objc_msgSend这玩意.objc_msgSend实现有很多个版本,大体逻辑应该差不多,首先在找缓存,找到就跳转过去,找不到就在Class的方法列表里找方法,如果还是没找到就转发.

    下的是arm下的代码

    ENTRY objc_msgSend 

    # check whether receiver is nil  

        teq     a1, #0 

        itt eq 

        moveq   a2, #0 

        bxeq    lr 

    # save registers and load receiver's class forCacheLookup  

        stmfd   sp!, {a4,v1} 

        ldr     v1, [a1, #ISA] 

    # receiver is non-nil: search the cache  

        CacheLookup a2,v1, LMsgSendCacheMiss 

    # cache hit (imp in ip) and CacheLookup returns withnonstret (eq) set, restore registers and call  

        ldmfd   sp!, {a4,v1} 

        bx      ip 

    # cache miss: go search the method lists  

    LMsgSendCacheMiss: 

        ldmfd   sp!, {a4,v1} 

        b   _objc_msgSend_uncached 

    LMsgSendExit: 

        END_ENTRY objc_msgSend 

        STATIC_ENTRY objc_msgSend_uncached 

    # Push stack frame  

        stmfd   sp!, {a1-a4,r7,lr} 

        add     r7, sp, #16 

    # Load class and selector  

        ldr a1, [a1,#ISA]      /* class = receiver->isa  */ 

        # MOVE  a2, a2          /* selector already in a2 */  

    # Do the lookup  

       MI_CALL_EXTERNAL(__class_lookupMethodAndLoadCache) 

        MOVE    ip, a1 

    # Prep for forwarding, Pop stack frame and call imp  

        teq v1, v1      /*set nonstret (eq) */ 

        ldmfd   sp!, {a1-a4,r7,lr} 

        bx  ip 

    1.2.12 conformsTo:

        返回是否遵循了某个协议

    - (BOOL) conformsTo: (Protocol *)aProtocolObj 

          return [(id)isa conformsTo: aProtocolObj]; 

    + (BOOL) conformsTo: (Protocol *)aProtocolObj 

          Class class; 

          for (class = self; class; class = class_getSuperclass(class)) 

        { 

              if(class_conformsToProtocol(class, aProtocolObj)) return YES; 

        } 

         return NO; 

        最终用的是class_conformsToProtocol,返回一个布尔值,表示一个类是否符合给定的协议。

    class_conformsToProtocol的实现如下:

    BOOL class_conformsToProtocol(Class cls_gen, Protocol*proto_gen) 

        struct old_class *cls = oldcls(cls_gen); 

        struct old_protocol *proto = oldprotocol(proto_gen); 

        if (!cls_gen) return NO; 

        if (!proto) returnNO; 

        if(cls->isa->version >= 3) { 

            structold_protocol_list *list; 

            for (list =cls->protocols; list != NULL; list = list->next) { 

                int i; 

                for (i =0; i < list->count; i++) { 

                    if(list->list[i] == proto) return YES; 

                    if(protocol_conformsToProtocol((Protocol *)list->list[i], proto_gen)) 

                        return YES; 

                } 

                if(cls->isa->version <= 4) break; 

            } 

        } 

        return NO; 

            可以看到是在cls->protocols里面找.protocols是协议的数组

    1.2.13 copy

    浅拷贝

    - copy  

        return [self copyFromZone: [self zone]]; 

    //返回指定区域的指针  

    - (voidvoid *)zone 

        void *z = malloc_zone_from_ptr(self); 

        return z ? z :malloc_default_zone(); 

    - copyFromZone:(voidvoid *)z 

        return (*_zoneCopy)(self, 0, z);  

    id (*_zoneCopy)(id, size_t, void *) =_object_copyFromZone; 

    static id _object_copyFromZone(id oldObj, size_t extraBytes,voidvoid *zone)  

        id obj; 

        size_t size; 

        if (!oldObj) return nil; 

        //用旧对象的isa生成一个新的对象的空间  

        obj = (*_zoneAlloc)(oldObj->isa, extraBytes, zone); 

        size =_class_getInstanceSize(oldObj->isa) + extraBytes; 

        // fixme need C++copy constructor  

        //把旧对象的内存拷贝到新对象  

       objc_memmove_collectable(obj, oldObj, size); 

    2 概念原理

    2.1 野指针与僵尸对象

    2.1.1 野指针

    C语言:

           当我们声明1个指针变量,没有为这个指针变量赋初始值.这个指针变量的值是1个垃圾指指针,指向1块随机的内存空间。

    OC语言:

            指针指向的对象已经被回收掉了。这个指针就叫做野指针。

    2.1.2 僵尸对象

    僵尸对象:

        1个已经被释放的对象 就叫做僵尸对象.

    2.2 nil/Nil/NULL/NSNull的区别

        nil:指向oc中对象的空指针

        Nil:指向oc中类的空指针

        NULL:指向其他类型的空指针,如一个c类型的内存指针

        NSNull:在集合对象中,表示空值的对象

        若obj为nil:

            [obj message]将返回NO,而不是NSException

        若obj为NSNull:

           [obj message]将抛出异常NSException

            nil和NULL从字面意思来理解比较简单,nil是一个对象,而NULL是一个值,我的理解为nil是将对象设置为空,而NULL是将基本类型设置为空的。而且我们对于nil调用方法,不会产生crash或者抛出异常。

    看一下用法

    NSURL *url = nil;

    Class class = Nil;

    int *pointerInt = NULL;

    nil是一个对象指针为空,Nil是一个类指针为空,NULL是基本数据类型为空。

    3 参考链接

    IOS中类和对象还有,nil/Nil/NULL的区别

    http://blog.sina.com.cn/s/blog_5fb39f910101akm1.html

    cancelPreviousPerformRequestsWithTarget not cancelling anoutstanding performSelector:withDelay

    http://stackoverflow.com/questions/8697648/cancelpreviousperformrequestswithtarget-not-cancelling-an-outstanding-performsel

    iOS设置 延迟执行 与 取消延迟执行 方法 以及对runloop初步认识

    http://www.cnblogs.com/someonelikeyou/p/5509878.html

    IOS关于取消延迟执行函数的种种。performSelector与cancelPreviousPerformRequestsWithTarget

    http://blog.csdn.net/samuelltk/article/details/8994313

    IOS -延迟执行performSelector和取消延迟执行cancelPreviousPerformRequestsWithTarget

    http://www.cnblogs.com/HermitCarb/p/4740773.html

    相关文章

      网友评论

        本文标题:【IOS开发高级系列】NSObject专题

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