深入理解objc的功能莫过于理解objc的源码,最新源码objc下载地址。
NSObject结构分析
NSObject结构定义在NSObject.h
文件中,通过查看其定义知其含有一个Class类型对象,其结构定义为
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
/// An opaque type that represents an Objective-C class
typedef struct objc_class *Class;
在Objc中,老版本objc_class的定义为
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocol OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
新版本objc_class的定义为
struct objc_class : objc_object {
Class superclass;
const char *name;
uint32_t version;
uint32_t info;
uint32_t instance_size;
struct old_ivar_list *ivars;
struct old_method_list **methodLists;
Cache cache;
struct old_protocol_list *protocols;
// CLS_EXT only
const uint8_t *ivar_layout;
struct old_class_ext *ext;
...
};
struct objc_object {
private:
isa_t isa;
public:
...
};
union isa_t
{
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits;
};
NSObject方法及协议分析
- hash
- dealloc
- 消息转发
- 内存管理
- 拷贝
hash方法分析
通过查看apple的runtime源码,发现NSObject执行hash
方法时调用了_objc_rootHash
方法返回当前对象的指针的整形数据,该函数的实现如下
#ifndef _UINTPTR_T
#define _UINTPTR_T
typedef unsigned long uintptr_t;
#endif /* _UINTPTR_T */
uintptr_t _objc_rootHash(id obj)
{
return (uintptr_t)obj;
}
通过测试代码可以验证hash返回该对象指针数据的整形值,测试代码如下所示:
NSObject *obj = [[NSObject alloc] init];
NSLog(@"hash = %lu, selfPointer = %p", (unsigned long)[obj hash], obj);
2016-12-27 09:55:57.082 demo[3545:56563] hash = 140686818358448, selfPointer = 0x7ff433d534b0
dealoc方法分析
通过apple的runtime源代码,发现NSObject执行dealloc
时调用_objc_rootDealloc
,再调用objc_object对象的rootDealloc
,继续调用object_dispose
,在继续调用_object_dispose
方法,这个方法的源码如下所示:
/**************************************************
* objc_destructInstance
* Destroys an instance without freeing memory.
* Calls C++ destructors.
* Removes associative references.
* Returns `obj`. Does nothing if `obj` is nil.
* CoreFoundation and other clients do call this under GC.
***************************************************/
void *objc_destructInstance(id obj)
{
if (obj) {
Class isa = obj->getIsa();
if (isa->hasCxxDtor()) {
object_cxxDestruct(obj);
}
if (isa->instancesHaveAssociatedObjects()) {
_object_remove_assocations(obj);
}
objc_clear_deallocating(obj);
}
return obj;
}
这个函数简单的做了3件事情:
1 查询当前对象是否存在C++的析构函数,如果有则执行object_cxxDestruct
函数
2 查询当前对象是否有关联的对象,如果有则执行_object_remove_assocations
函数
3 执行objc_clear_deallocating
函数
通过调试程序时对属性的观察可知,在ARC下变量的释放就是在.cxx_struct
,其测试的代码是观察类的某个属性,其lldb下的代码:
(lldb) watchpoint set variable self->_name
Watchpoint created: Watchpoint 1: addr = 0x7ff73142f0a8 size = 8 state = enabled type = w
watchpoint spec = 'self->_name'
new value: 0x0000000108f751b0
2016-12-27 11:12:25.187 demo[5544:99205] IMP: -[NSObject (demo) foo]
2016-12-27 11:12:31.187 demo[5544:99205] 140699660120224, 0x7ff73142f0a0
Watchpoint 1 hit:
old value: 0x0000000108f751b0
new value: 0x0000000000000000
(lldb)
发现果然跟到了.cxx_destruct
方法,而且是在objc_storeStrong
的过程中释放。
object_cxxDestruct函数分析
通过Apple的源代码可以查看到,它主要调用<font color=#D2691E">object_cxxDestructFromClass
</font>函数实现,该函数的实现源码如下:
/***************************************************
* object_cxxDestructFromClass.
* Call C++ destructors on obj, starting with cls's
* dtor method (if any) followed by superclasses' dtors (if any),
* stopping at cls's dtor (if any).
* Uses methodListLock and cacheUpdateLock. The caller must hold neither.
***************************************************/
static void object_cxxDestructFromClass(id obj, Class cls)
{
void (*dtor)(id);
// Call cls's dtor first, then superclasses's dtors.
for ( ; cls; cls = cls->superclass) {
if (!cls->hasCxxDtor()) return;
dtor = (void(*)(id)lookupMethodInClassAndLoadCache(cls, SEL_cxx_destruct);
if (dtor != (void(*)(id))_objc_msgForward_impcache) {
if (PrintCxxCtors) {
_objc_inform("CXX: calling C++ destructors for class %s",
cls->nameForLogging());
}
(*dtor)(obj);
}
}
}
代码也不难理解,沿着继承链逐层向上搜寻<font color=#D2691E >SEL_cxx_destruct</font>这个selector,找到函数实现(void (*)(id)(函数指针)并执行
_object_remove_assocation函数分析
通过Apple的源代码查看_object_remove_assocation
,其代码如下所示
void _object_remove_assocations(id object) {
vector< ObjcAssociation,ObjcAllocator<ObjcAssociation> > elements;
{
AssociationsManager manager; //全局的对象
AssociationsHashMap &associations(manager.associations());
if (associations.size() == 0) return;
disguised_ptr_t disguised_object = DISGUISE(object);
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
// copy all of the associations that need to be removed.
ObjectAssociationMap *refs = i->second;
for (ObjectAssociationMap::iterator j = refs->begin(), end = refs->end(); j != end; ++j) {
elements.push_back(j->second);
}
// remove the secondary table.
delete refs;
associations.erase(i);
}
}
// the calls to releaseValue() happen outside of the lock.
for_each(elements.begin(), elements.end(), ReleaseValue());
}
objc_clear_deallocating函数分析
通过Apple的源代码查看可获知其调用了clearDeallocating
,然后在调用sidetable_clearDeallocating
,该函数的源码如下所示:
void
objc_object::sidetable_clearDeallocating()
{
SideTable& table = SideTables()[this];
// clear any weak table items
// clear extra retain count and deallocating bit
// (fixme warn or abort if extra retain count == 0 ?)
table.lock();
RefcountMap::iterator it = table.refcnts.find(this);
if (it != table.refcnts.end()) {
if (it->second & SIDE_TABLE_WEAKLY_REFERENCED) {
weak_clear_no_lock(&table.weak_table, (id)this);
}
table.refcnts.erase(it);
}
table.unlock();
}
消息转发
在NSObject中performSelector只是将方法做个转发功能,其内部代码主要是调用objc_msgSend
实现,源码实现如下
+ (id)performSelector:(SEL)sel {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL))objc_msgSend)((id)self, sel);
}
+ (id)performSelector:(SEL)sel withObject:(id)obj {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL, id))objc_msgSend)((id)self, sel, obj);
}
+ (id)performSelector:(SEL)sel withObject:(id)obj1 withObject:(id)obj2 {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL, id, id))objc_msgSend)((id)self, sel, obj1, obj2);
}
- (id)performSelector:(SEL)sel {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL))objc_msgSend)(self, sel);
}
- (id)performSelector:(SEL)sel withObject:(id)obj {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL, id))objc_msgSend)(self, sel, obj);
}
- (id)performSelector:(SEL)sel withObject:(id)obj1 withObject:(id)obj2 {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL, id, id))objc_msgSend)(self, sel, obj1, obj2);
}
在NSObject上forwardInvocation方法只是简单调用NSInvocation的selector方法,其源码如下
+ (void)forwardInvocation:(NSInvocation *)invocation {
[self doesNotRecognizeSelector:(invocation ? [invocation selector] : 0)];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
[self doesNotRecognizeSelector:(invocation ? [invocation selector] : 0)];
}
内存管理
NSObject的内存管理主要是通过引用计数来实现,那retain、release、autorelease等是如何实现这些计数的呢?
- retain剖析
- release剖析
- autorelease剖析
retain剖析
NSObject的retain的源码如下
+ (id)retain {
return (id)self;
}
// Replaced by ObjectAlloc
- (id)retain {
return ((id)self)->rootRetain();
}
继续查看rootRetain的源码,调用的objc_object的rootRetain方法
inline id objc_object::rootRetain()
{
if (isTaggedPointer()) return (id)this;
return sidetable_retain();
}
在查看sidetable_retain的源码
id objc_object::sidetable_retain()
{
#if SUPPORT_NONPOINTER_ISA
assert(!isa.nonpointer);
#endif
SideTable& table = SideTables()[this];
table.lock();
size_t& refcntStorage = table.refcnts[this];
if (! (refcntStorage & SIDE_TABLE_RC_PINNED)) {
refcntStorage += SIDE_TABLE_RC_ONE;
}
table.unlock();
return (id)this;
}
这是我们看到SideTables对象,这个对象是干什么的呢?看起源码
struct SideTable {
spinlock_t slock;
RefcountMap refcnts;
weak_table_t weak_table;
...
};
在该结构体内包含个weak_table_t结构,查看其结构时
/**
* The global weak references table. Stores object ids as keys,
* and weak_entry_t structs as their values.
*/
struct weak_table_t {
weak_entry_t *weak_entries;
size_t num_entries;
uintptr_t mask;
uintptr_t max_hash_displacement;
};
其中的weak_entry_t的源码如下所示
struct weak_entry_t {
DisguisedPtr<objc_object> referent;
union {
struct {
weak_referrer_t *referrers;
uintptr_t out_of_line_ness : 2;
uintptr_t num_refs : PTR_MINUS_2;
uintptr_t mask;
uintptr_t max_hash_displacement;
};
struct {
// out_of_line_ness field is low bits of inline_referrers[1]
weak_referrer_t inline_referrers[WEAK_INLINE_COUNT];
};
};
bool out_of_line() {
return (out_of_line_ness == REFERRERS_OUT_OF_LINE);
}
weak_entry_t& operator=(const weak_entry_t& other) {
memcpy(this, &other, sizeof(other));
return *this;
}
weak_entry_t(objc_object *newReferent, objc_object **newReferrer)
: referent(newReferent)
{
inline_referrers[0] = newReferrer;
for (int i = 1; i < WEAK_INLINE_COUNT; i++) {
inline_referrers[i] = nil;
}
}
};
release剖析
NSObject的release的源码如下
// Replaced by ObjectAlloc
- (oneway void)release {
((id)self)->rootRelease();
}
+ (id)autorelease {
return (id)self;
}
NSObject的autorelease的源码如下
// Replaced by ObjectAlloc
- (id)autorelease {
return ((id)self)->rootAutorelease();
}
autorelease剖析
NSObject函数在调用autorelease时,其内部其实是调用AutoreleasePoolPage函数实现内存管理
// Replaced by ObjectAlloc
- (id)autorelease {
return ((id)self)->rootAutorelease();
}
// Base autorelease implementation, ignoring overrides.
inline id objc_object::rootAutorelease()
{
if (isTaggedPointer()) return (id)this;
if (prepareOptimizedReturn(ReturnAtPlus1)) return (id)this;
return rootAutorelease2();
}
而rootAutorelease2
方法是调用
__attribute__((noinline,used)) id objc_object::rootAutorelease2()
{
assert(!isTaggedPointer());
return AutoreleasePoolPage::autorelease((id)this);
}
往下看autorelease
的实现
static inline id autorelease(id obj)
{
assert(obj);
assert(!obj->isTaggedPointer());
id *dest __unused = autoreleaseFast(obj);
assert(!dest || dest == EMPTY_POOL_PLACEHOLDER || *dest == obj);
return obj;
}
接着看autoreleaseFast
函数的实现
static inline id *autoreleaseFast(id obj)
{
AutoreleasePoolPage *page = hotPage();
if (page && !page->full()) {
return page->add(obj);
} else if (page) {
return autoreleaseFullPage(obj, page);
} else {
return autoreleaseNoPage(obj);
}
}
id *add(id obj)
{
assert(!full());
unprotect();
id *ret = next; // faster than `return next-1` because of aliasing
*next++ = obj;
protect();
return ret;
}
static __attribute__((noinline)) id *autoreleaseNoPage(id obj)
{
...
// Install the first page.
AutoreleasePoolPage *page = new AutoreleasePoolPage(nil);
setHotPage(page);
// Push a boundary on behalf of the previously-placeholder'd pool.
if (pushExtraBoundary) {
page->add(POOL_BOUNDARY);
}
// Push the requested object or pool.
return page->add(obj);
}
可以了解到开始创建了AutoreleasePoolPage对象,第一次没有page时,将调用autoreleaseNoPage创建个page,将对象加入到page中。只要当前的hotPage不满,直接将其加入当前的page中。否则调用autoreleaseFullPage重新申请新的page,将对象加入其中。
对于AutoreleasePoolPage到底是什么呢?
class AutoreleasePoolPage
{
....
magic_t const magic;
id *next;
pthread_t const thread;
AutoreleasePoolPage * const parent;
AutoreleasePoolPage *child;
uint32_t const depth;
uint32_t hiwat;
...
};