Objective-C 【NSObject 的实现分析】

来源:互联网 发布:实现数据库的增删改查 编辑:程序博客网 时间:2024/06/06 07:46

NSObject 的实现分析


iOS 的 NSObject 类没有开源, 但是呢 runtime 开源了,里面有个类 Object 看接口和NSObject差不多,下面我就对着 Object 的代码来分析下 NSObject

runtime代码在http://opensource.apple.com/tarballs/objc4/objc4-493.9.tar.gz下载,Object在<Object.h>, 这里的文件夹写着Obsolete, 呃.

属性

isa

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

方法

class

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

代码实现如下:

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. class  
  2. {  
  3.     return (id)isa;   
  4. }  
  5.   
  6. class   
  7. {  
  8.     return self;  
  9. }  

superclass

返回父类

代码实现如下:

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. + superclass   
  2. {   
  3.     return class_getSuperclass((Class)self);   
  4. }  
  5.   
  6. - superclass   
  7. {   
  8.     return class_getSuperclass(isa);   
  9. }  

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

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static class_t *  
  2. getSuperclass(class_t *cls)  
  3. {  
  4.     if (!cls) return NULL;  
  5.     return cls->superclass;  
  6. }  

isEqual

就是直接比较

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. - (BOOL)isEqual:anObject  
  2. {  
  3.     return anObject == self;   
  4. }  

isMemberOf:

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. - (BOOL)isMemberOf:aClass  
  2. {  
  3.     return isa == (Class)aClass;  
  4. }  

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

isKindOf:

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. - (BOOL)isKindOf:aClass  
  2. {  
  3.     register Class cls;  
  4.     for (cls = isa; cls; cls = class_getSuperclass(cls))   
  5.         if (cls == (Class)aClass)  
  6.             return YES;  
  7.     return NO;  
  8. }  
  9.   
  10. // class_getSuperclass 展开后如下  
  11. static class_t *  
  12. getSuperclass(class_t *cls)  
  13. {  
  14.     if (!cls) return NULL;  
  15.     return cls->superclass;  
  16. }  

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

init

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. - init  
  2. {  
  3.     return self;  
  4. }  

没什么好说的

alloc

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. + alloc  
  2. {  
  3.     return (*_zoneAlloc)((Class)self0, malloc_default_zone());   
  4. }  

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

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. id (*_zoneAlloc)(Class, size_tvoidvoid *) = _class_createInstanceFromZone;  
  2.   
  3. PRIVATE_EXTERN id   
  4. _class_createInstanceFromZone(Class cls, size_t extraBytes, voidvoid *zone)  
  5. {  
  6.     id obj;  
  7.     size_t size;  
  8.   
  9.     // Can't create something for nothing  
  10.     if (!cls) return nil;  
  11.   
  12.     // Allocate and initialize  
  13.     size = _class_getInstanceSize(cls) + extraBytes;  
  14.   
  15.     // CF requires all objects be at least 16 bytes.  
  16.     if (size < 16) size = 16;  
  17.   
  18. #if SUPPORT_GC  
  19.     if (UseGC) {  
  20.         obj = (id)auto_zone_allocate_object(gc_zone, size,  
  21.                                             AUTO_OBJECT_SCANNED, 01);  
  22.     } else   
  23. #endif  
  24.     if (zone) {  
  25.         obj = (id)malloc_zone_calloc (zone, 1, size);  
  26.     } else {  
  27.         obj = (id)calloc(1, size);  
  28.     }  
  29.     if (!obj) return nil;  
  30.   
  31.     obj->isa = cls;  
  32.   
  33.     if (_class_hasCxxStructors(cls)) {  
  34.         obj = _objc_constructOrFree(cls, obj);  
  35.     }  
  36.   
  37.     return obj;  
  38. }  

上面那段代码的作用是

  1. 得到这个类占用多少空间,最小占16 bytes
  2. 然后就给这个实例分配多少空间, 如果失败的话就返回nil
  3. 把这个实例的isa设置成这个类对象
  4. 如果cls的info设置了get属性就用cls这个类在obj这个空间去构造一个实例,跟进去是
[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static BOOL object_cxxConstructFromClass(id obj, Class cls)  
  2. {  
  3.     id (*ctor)(id);  
  4.     Class supercls;  
  5.   
  6.     // Stop if neither this class nor any superclass has ctors.  
  7.     if (!_class_hasCxxStructors(cls)) return YES;  // no ctor - ok  
  8.   
  9.     supercls = _class_getSuperclass(cls);  
  10.   
  11.     // Call superclasses' ctors first, if any.  
  12.     if (supercls) {  
  13.         BOOL ok = object_cxxConstructFromClass(obj, supercls);  
  14.         if (!ok) return NO;  // some superclass's ctor failed - give up  
  15.     }  
  16.   
  17.     // Find this class's ctor, if any.  
  18.     ctor = (id(*)(id))lookupMethodInClassAndLoadCache(cls, SEL_cxx_construct);  
  19.     if (ctor == (id(*)(id))&_objc_msgForward_internal) return YES;  // no ctor - ok  
  20.   
  21.     // Call this class's ctor.  
  22.     if (PrintCxxCtors) {  
  23.         _objc_inform("CXX: calling C++ constructors for class %s", _class_getName(cls));  
  24.     }  
  25.     if ((*ctor)(obj)) return YES;  // ctor called and succeeded - ok  
  26.   
  27.     // This class's ctor was called and failed.   
  28.     // Call superclasses's dtors to clean up.  
  29.     if (supercls) object_cxxDestructFromClass(obj, supercls);  
  30.     return NO;  
  31. }  

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

new

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. new  
  2. {  
  3.     id newObject = (*_alloc)((Class)self0);  
  4.     Class metaClass = self->isa;  
  5.     if (class_getVersion(metaClass) > 1)  
  6.         return [newObject init];  
  7.     else  
  8.         return newObject;  
  9. }  

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

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. id (*_alloc)(Class, size_t) = _class_createInstance;  
  2.   
  3. static id _class_createInstance(Class cls, size_t extraBytes)  
  4. {  
  5.     return _class_createInstanceFromZone (cls, extraBytes, NULL);  
  6. }  

free

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. - free   
  2. {   
  3.     return (*_dealloc)(self);   
  4. }  
  5.   
  6. + free  
  7. {  
  8.     return nil;   
  9. }  

跟进去看一下

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static id   
  2. _object_dispose(id anObject)   
  3. {  
  4.     if (anObject==nilreturn nil;  
  5.   
  6.     objc_destructInstance(anObject);  
  7.   
  8. #if SUPPORT_GC  
  9.     if (UseGC) {  
  10.         auto_zone_retain(gc_zone, anObject); // gc free expects rc==1  
  11.     } else   
  12. #endif  
  13.     {  
  14.         // only clobber isa for non-gc  
  15.         anObject->isa = _objc_getFreedObjectClass ();   
  16.     }  
  17.     free(anObject);  
  18.     return nil;  
  19. }  
  20.   
  21. voidvoid *objc_destructInstance(id obj)   
  22. {  
  23.     if (obj) {  
  24.         Class isa = _object_getClass(obj);  
  25.   
  26.         if (_class_hasCxxStructors(isa)) {  
  27.             object_cxxDestruct(obj);  
  28.         }  
  29.   
  30.         if (_class_instancesHaveAssociatedObjects(isa)) {  
  31.             _object_remove_assocations(obj);  
  32.         }  
  33.   
  34.         if (!UseGC) objc_clear_deallocating(obj);  
  35.     }  
  36.   
  37.     return obj;  
  38. }  
  1. 执行一个叫object_cxxDestruct的东西干了点什么事(沿着继承链逐层向上搜寻SEL_cxx_destruct这个selector, 找到函数实现(void (*)(id)(函数指针)并执行)
  2. 执行_object_remove_assocations去除和这个对象关联的对象
  3. 执行objc_clear_deallocating,清空引用计数表并清除弱引用表,将所有weak引用指nil

respondsTo:

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

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. - (BOOL)respondsTo:(SEL)aSelector   
  2. {  
  3.     return class_respondsToMethod(isa, aSelector);  
  4. }  
  5.   
  6. BOOL class_respondsToMethod(Class cls, SEL sel)  
  7. {  
  8.     OBJC_WARN_DEPRECATED;  
  9.   
  10.     return class_respondsToSelector(cls, sel);  
  11. }  
  12.   
  13. BOOL class_respondsToSelector(Class cls, SEL sel)  
  14. {  
  15.     IMP imp;  
  16.   
  17.     if (!sel  ||  !cls) return NO;  
  18.   
  19.     // Avoids +initialize because it historically did so.  
  20.     // We're not returning a callable IMP anyway.  
  21.     imp = lookUpMethod(cls, sel, NO/*initialize*/YES/*cache*/);  
  22.     return (imp != (IMP)_objc_msgForward_internal) ? YES : NO;  
  23. }  

perform:

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

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. - perform:(SEL)aSelector   
  2. {   
  3.     if (aSelector)  
  4.         return objc_msgSend(self, aSelector);   
  5.     else  
  6.         return [self error:_errBadSel, sel_getName(_cmd), aSelector];  
  7. }  

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

下的是arm下的代码

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. ENTRY objc_msgSend  
  2. # check whether receiver is nil  
  3.     teq     a1, #0  
  4.     itt eq  
  5.     moveq   a2, #0  
  6.     bxeq    lr  
  7.   
  8. # save registers and load receiver's class for CacheLookup  
  9.     stmfd   sp!, {a4,v1}  
  10.     ldr     v1, [a1, #ISA]  
  11.   
  12. # receiver is non-nil: search the cache  
  13.     CacheLookup a2, v1, LMsgSendCacheMiss  
  14.   
  15. # cache hit (imp in ip) and CacheLookup returns with nonstret (eq) set, restore registers and call  
  16.     ldmfd   sp!, {a4,v1}  
  17.     bx      ip  
  18.   
  19. # cache miss: go search the method lists  
  20. LMsgSendCacheMiss:  
  21.     ldmfd   sp!, {a4,v1}  
  22.     b   _objc_msgSend_uncached  
  23.   
  24. LMsgSendExit:  
  25.     END_ENTRY objc_msgSend  
  26.   
  27.   
  28.     STATIC_ENTRY objc_msgSend_uncached  
  29.   
  30. # Push stack frame  
  31.     stmfd   sp!, {a1-a4,r7,lr}  
  32.     add     r7, sp, #16  
  33.   
  34. # Load class and selector  
  35.     ldr a1, [a1, #ISA]      /* class = receiver->isa  */  
  36.     # MOVE  a2, a2          /* selector already in a2 */  
  37.   
  38. # Do the lookup  
  39.     MI_CALL_EXTERNAL(__class_lookupMethodAndLoadCache)  
  40.     MOVE    ip, a1  
  41.   
  42. # Prep for forwarding, Pop stack frame and call imp  
  43.     teq v1, v1      /* set nonstret (eq) */  
  44.     ldmfd   sp!, {a1-a4,r7,lr}  
  45.     bx  ip  

conformsTo:

返回是否遵循了某个协议

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. - (BOOL) conformsTo: (Protocol *)aProtocolObj  
  2. {  
  3.   return [(id)isa conformsTo:aProtocolObj];  
  4. }  
  5.   
  6. + (BOOL) conformsTo: (Protocol *)aProtocolObj  
  7. {  
  8.   Class class;  
  9.   for (class = selfclassclass = class_getSuperclass(class))  
  10.     {  
  11.       if (class_conformsToProtocol(class, aProtocolObj)) return YES;  
  12.     }  
  13.   return NO;  
  14. }  

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

class_conformsToProtocol的实如下

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. BOOL class_conformsToProtocol(Class cls_gen, Protocol *proto_gen)  
  2. {  
  3.     struct old_class *cls = oldcls(cls_gen);  
  4.     struct old_protocol *proto = oldprotocol(proto_gen);  
  5.   
  6.     if (!cls_gen) return NO;  
  7.     if (!proto) return NO;  
  8.   
  9.     if (cls->isa->version >= 3) {  
  10.         struct old_protocol_list *list;  
  11.         for (list = cls->protocols; list != NULL; list = list->next) {  
  12.             int i;  
  13.             for (i = 0; i < list->count; i++) {  
  14.                 if (list->list[i] == proto) return YES;  
  15.                 if (protocol_conformsToProtocol((Protocol *)list->list[i], proto_gen)) return YES;  
  16.             }  
  17.             if (cls->isa->version <= 4break;  
  18.         }  
  19.     }  
  20.     return NO;  
  21. }  

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

copy

浅拷贝


[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. copy   
  2. {  
  3.     return [self copyFromZone: [self zone]];  
  4. }  
  5.   
  6. // 返回指定区域的指针  
  7. - (voidvoid *)zone  
  8. {  
  9.     voidvoid *z = malloc_zone_from_ptr(self);  
  10.     return z ? z : malloc_default_zone();  
  11. }  
  12.   
  13. - copyFromZone:(voidvoid *)z  
  14. {  
  15.     return (*_zoneCopy)(self0, z);   
  16. }  
  17.   
  18. id (*_zoneCopy)(idsize_tvoidvoid *) = _object_copyFromZone;  
  19.   
  20. static id _object_copyFromZone(id oldObj, size_t extraBytes, voidvoid *zone)   
  21. {  
  22.     id obj;  
  23.     size_t size;  
  24.   
  25.     if (!oldObj) return nil;  
  26.   
  27.     // 用旧对象的isa生成一个新的对象的空间  
  28.     obj = (*_zoneAlloc)(oldObj->isa, extraBytes, zone);  
  29.     size = _class_getInstanceSize(oldObj->isa) + extraBytes;  
  30.       
  31.     // fixme need C++ copy constructor  
  32.     // 把旧对象的内存拷贝到新对象  
  33.     objc_memmove_collectable(obj, oldObj, size);  
  34.       
  35. }  
0 0