笔者整理了一系列有关OC的底层文章,但愿能够帮助到你。c++
1.iOS的OC对象建立的alloc原理swift
2.iOS的OC对象的内存对齐数组
3.iOS的OC的isa的底层原理缓存
4.iOS的OC源码分析之类的结构分析bash
5.iOS的OC的方法缓存的源码分析app
6.iOS的OC的方法的查找原理函数
7.iOS的OC的方法的决议与消息转发原理oop
8.iOS的App的加载流程源码分析
在dyld
的加载流程中,从dyld源码
过分到objc源码
的过程是在objc_init
这个函数。接下来会先介绍objc_init
。post
void _objc_init(void)
{
static bool initialized = false;
if (initialized) return;
initialized = true;
// fixme defer initialization until an objc-using image is found?
environ_init();
tls_init();
static_init();
lock_init();
exception_init();
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
}
复制代码
_objc_init
函数是在运行时
执行到的,下面对里面的各个函数的简单介绍。
Xcode
中设置打印出来。key
的绑定。好比线程数据的析构函数。c++
的构造函数。c++
层面的锁也适合oc
(只是猜测)。_objc_terminate
。dyld
加载映射回调到objc
的函数,而且这个也是_objc_init
函数中最主要的函数。接下来就是对_dyld_objc_notify_register
函数中的map_images
来作详细的介绍,而且类的加载
也是在这里。
void
map_images(unsigned count, const char * const paths[],
const struct mach_header * const mhdrs[])
{
mutex_locker_t lock(runtimeLock);
return map_images_nolock(count, paths, mhdrs);
}
void
map_images_nolock(unsigned mhCount, const char * const mhPaths[],
const struct mach_header * const mhdrs[])
{
.....省略部分代码.......
// Find all images with Objective-C metadata.
hCount = 0;
// Count classes. Size various table based on the total.
int totalClasses = 0;
int unoptimizedTotalClasses = 0;
.....省略部分代码.......
if (hCount > 0) {
_read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
}
}
复制代码
在map_images
函数中调用map_images_nolock
函数,其中_read_images
函数是这些函数中最重要的。由函数名称能够知道是读取镜像
文件到内存中。
因为_read_images
代码过多,只能部分代码来解析。
if (!doneOnce) {
doneOnce = YES;
...省略部分代码..
if (DisableTaggedPointers) {
disableTaggedPointers();
}
initializeTaggedPointerObfuscator();
if (PrintConnecting) {
_objc_inform("CLASS: found %d classes during launch", totalClasses);
}
// namedClasses
// Preoptimized classes don't go in this table. // 4/3 is NXMapTable's load factor
int namedClassesSize =
(isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;
gdb_objc_realized_classes =
NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);
allocatedClasses = NXCreateHashTable(NXPtrPrototype, 0, nil);
ts.log("IMAGE TIMES: first time tasks");
}
// This is a misnomer: gdb_objc_realized_classes is actually a list of
// named classes not in the dyld shared cache, whether realized or not.
NXMapTable *gdb_objc_realized_classes; // exported for debuggers in objc-gdb.h
/***********************************************************************
* allocatedClasses
* A table of all classes (and metaclasses) which have been allocated
* with objc_allocateClassPair.
**********************************************************************/
static NXHashTable *allocatedClasses = nil;
复制代码
doneOnce
只是执行一次,若是是初次进来的就会执行括号里面的代码。 initializeTaggedPointerObfuscator()
这个函数是对TaggedPointer
作优化的。其中gdb_objc_realized_classes
和allocatedClasses
是两张哈希表,gdb_objc_realized_classes
这张表保存的是主要不是共享缓存
里面的类,不管实现了仍是没有实现的类都在这张表里面;allocatedClasses
这张表保存的是全部被分配内存后的类和元类。从中能够看出gdb_objc_realized_classes
是包含了allocatedClasses
的内容。
// Discover classes. Fix up unresolved future classes. Mark bundle classes.
for (EACH_HEADER) {
// 从编译后的类列表中取出全部类,获取到的是一个classref_t类型的指针
classref_t *classlist = _getObjc2ClassList(hi, &count);
if (! mustReadClasses(hi)) {
// Image is sufficiently optimized that we need not call readClass()
continue;
}
bool headerIsBundle = hi->isBundle();
bool headerIsPreoptimized = hi->isPreoptimized();
for (i = 0; i < count; i++) {
// 数组中会取出OS_dispatch_queue_concurrent、OS_xpc_object、NSRunloop等系统类,例如CF、Fundation、libdispatch中的类。以及本身建立的类
Class cls = (Class)classlist[i];
// 经过readClass函数获取处理后的新类,
Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
// 初始化全部懒加载的类须要的内存空间 - 如今数据没有加载到的 - 连类都没有初始化的
if (newCls != cls && newCls) {
// Class was moved but not deleted. Currently this occurs
// only when the new class resolved a future class.
// Non-lazily realize the class below.
// 将懒加载的类添加到数组中
resolvedFutureClasses = (Class *)
realloc(resolvedFutureClasses,
(resolvedFutureClassCount+1) * sizeof(Class));
resolvedFutureClasses[resolvedFutureClassCount++] = newCls;
}
}
}
ts.log("IMAGE TIMES: discover classes");
复制代码
这段代码主要是从编译后的类列表中读取全部类的classref_t指针
,经过遍历出类地址cls
,经过readClass
函数读取编译器的类和元类信息。
Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized)
{
const char *mangledName = cls->mangledName();
if (missingWeakSuperclass(cls)) {
// No superclass (probably weak-linked).
// Disavow any knowledge of this subclass.
if (PrintConnecting) {
_objc_inform("CLASS: IGNORING class '%s' with "
"missing weak-linked superclass",
cls->nameForLogging());
}
addRemappedClass(cls, nil);
cls->superclass = nil;
return nil;
}
// Note: Class __ARCLite__'s hack does not go through here. // Class structure fixups that apply to it also need to be // performed in non-lazy realization below. // These fields should be set to zero because of the // binding of _objc_empty_vtable, but OS X 10.8's dyld
// does not bind shared cache absolute symbols as expected.
// This (and the __ARCLite__ hack below) can be removed
// once the simulator drops 10.8 support.
#if TARGET_OS_SIMULATOR
if (cls->cache._mask) cls->cache._mask = 0;
if (cls->cache._occupied) cls->cache._occupied = 0;
if (cls->ISA()->cache._mask) cls->ISA()->cache._mask = 0;
if (cls->ISA()->cache._occupied) cls->ISA()->cache._occupied = 0;
#endif
cls->fixupBackwardDeployingStableSwift();
Class replacing = nil;
if (Class newCls = popFutureNamedClass(mangledName)) {
// This name was previously allocated as a future class.
// Copy objc_class to future class's struct. // Preserve future's rw data block.
if (newCls->isAnySwift()) {
_objc_fatal("Can't complete future class request for '%s' "
"because the real class is too big.",
cls->nameForLogging());
}
class_rw_t *rw = newCls->data();
const class_ro_t *old_ro = rw->ro;
memcpy(newCls, cls, sizeof(objc_class));
rw->ro = (class_ro_t *)newCls->data();
newCls->setData(rw);
freeIfMutable((char *)old_ro->name);
free((void *)old_ro);
addRemappedClass(cls, newCls);
replacing = cls;
cls = newCls;
}
if (headerIsPreoptimized && !replacing) {
// class list built in shared cache
// fixme strict assert doesn't work because of duplicates // assert(cls == getClass(name)); assert(getClassExceptSomeSwift(mangledName)); } else { addNamedClass(cls, mangledName, replacing); addClassTableEntry(cls); } // for future reference: shared cache never contains MH_BUNDLEs if (headerIsBundle) { cls->data()->flags |= RO_FROM_BUNDLE; cls->ISA()->data()->flags |= RO_FROM_BUNDLE; } return cls; } static void addNamedClass(Class cls, const char *name, Class replacing = nil) { runtimeLock.assertLocked(); Class old; if ((old = getClassExceptSomeSwift(name)) && old != replacing) { inform_duplicate(name, old, cls); // getMaybeUnrealizedNonMetaClass uses name lookups. // Classes not found by name lookup must be in the // secondary meta->nonmeta table. addNonMetaClass(cls); } else { NXMapInsert(gdb_objc_realized_classes, name, cls); } assert(!(cls->data()->flags & RO_META)); // wrong: constructed classes are already realized when they get here // assert(!cls->isRealized()); } static void addClassTableEntry(Class cls, bool addMeta = true) { runtimeLock.assertLocked(); // This class is allowed to be a known class via the shared cache or via // data segments, but it is not allowed to be in the dynamic table already. assert(!NXHashMember(allocatedClasses, cls)); if (!isKnownClass(cls)) NXHashInsert(allocatedClasses, cls); if (addMeta) addClassTableEntry(cls->ISA(), false); } 复制代码
在readClass
函数中,if (Class newCls = popFutureNamedClass(mangledName))
这个判断的是对将来须要处理的类才会进入到if
条件的流程中,通常的状况下是不会进入这个流程的。而且这个函数中最主要的仍是执行了addNamedClass(cls, mangledName, replacing);
和addClassTableEntry(cls);
这两个函数,由源码能够知道,addNamedClass
函数是将类的名字和地址添加到gdb_objc_realized_classes
这个总的哈希表中,addClassTableEntry
函数是将类的地址添加到allocatedClasses
这张子的哈希表。此时就是将类的地址信息等插入到哈希表中了。从readClass
函数返回的Class
,再次回到Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
这段代码,其中在上面的源码中有newCls
和cls
对比的判断,意思就是若是从readClass
函数返回的newCls
和获取到的cls
不相等(只有在进入popFutureNamedClass
的判断条件才会不想等的,由于这里面对rw
中的ro
作了处理)。说明此时的newCls
与通常的类不同了,以后会执行到以下的源码:
// Realize newly-resolved future classes, in case CF manipulates them
if (resolvedFutureClasses) {
for (i = 0; i < resolvedFutureClassCount; i++) {
Class cls = resolvedFutureClasses[i];
if (cls->isSwiftStable()) {
_objc_fatal("Swift class is not allowed to be future");
}
realizeClassWithoutSwift(cls);
cls->setInstancesRequireRawIsa(false/*inherited*/);
}
free(resolvedFutureClasses);
}
ts.log("IMAGE TIMES: realize future classes");
复制代码
可是通常状况下是不会执行的。这个是将来须要特殊处理的而已。综合得出的是在readClass
函数中最要是判断当前的cls
是否是后期须要处理的类,若是是就要读取cls
的data()设置ro/rw(通常状况下不会的),而且将类的地址信息等分别插入到gdb_objc_realized_classes
和allocatedClasses
两张哈希表中。
// Fix up remapped classes
// Class list and nonlazy class list remain unremapped.
// Class refs and super refs are remapped for message dispatching.
if (!noClassesRemapped()) {
for (EACH_HEADER) {
// 重映射Class,注意是从_getObjc2ClassRefs函数中取出类的引用
Class *classrefs = _getObjc2ClassRefs(hi, &count);
for (i = 0; i < count; i++) {
remapClassRef(&classrefs[i]);
}
// fixme why doesn't test future1 catch the absence of this? classrefs = _getObjc2SuperRefs(hi, &count); for (i = 0; i < count; i++) { remapClassRef(&classrefs[i]); } } } 复制代码
这个代码块主要是修复类的重映射,就是将未映射的Class和Super Class重映射,其中被remap的类都是非懒加载的类
。这个代码块通常状况下是不会被执行到的。
// Fix up @selector references
static size_t UnfixedSelectors;
{
mutex_locker_t lock(selLock);
for (EACH_HEADER) {
if (hi->isPreoptimized()) continue;
bool isBundle = hi->isBundle();
SEL *sels = _getObjc2SelectorRefs(hi, &count);
UnfixedSelectors += count;
for (i = 0; i < count; i++) {
const char *name = sel_cname(sels[i]);
// 注册SEL的操做
sels[i] = sel_registerNameNoLock(name, isBundle);
}
}
}
ts.log("IMAGE TIMES: fix up selector references");
//====================
SEL sel_registerNameNoLock(const char *name, bool copy) {
return __sel_registerName(name, 0, copy); // NO lock, maybe copy
}
static SEL __sel_registerName(const char *name, bool shouldLock, bool copy)
{
SEL result = 0;
if (shouldLock) selLock.assertUnlocked();
else selLock.assertLocked();
if (!name) return (SEL)0;
result = search_builtins(name);
if (result) return result;
conditional_mutex_locker_t lock(selLock, shouldLock);
if (namedSelectors) {
result = (SEL)NXMapGet(namedSelectors, name);
}
if (result) return result;
// No match. Insert.
if (!namedSelectors) {
namedSelectors = NXCreateMapTable(NXStrValueMapPrototype,
(unsigned)SelrefCount);
}
if (!result) {
result = sel_alloc(name, copy);
// fixme choose a better container (hash not map for starters)
NXMapInsert(namedSelectors, sel_getName(result), result);
}
return result;
}
复制代码
这段代码就是将类
里面的方法的SEL
经过_getObjc2SelectorRefs
函数获取到SEL
数组从中获得方法的名字,而后经过sel_registerNameNoLock
函数再次调用__sel_registerName
函数,将方法名都注册到namedSelectors
这张哈希表中。
// Discover protocols. Fix up protocol refs.
// 遍历全部协议列表,而且将协议列表加载到Protocol的哈希表中
for (EACH_HEADER) {
extern objc_class OBJC_CLASS_$_Protocol;
// cls = Protocol类,全部协议和对象的结构体都相似,isa都对应Protocol类
Class cls = (Class)&OBJC_CLASS_$_Protocol;
assert(cls);
// 获取protocol哈希表
NXMapTable *protocol_map = protocols();
bool isPreoptimized = hi->isPreoptimized();
bool isBundle = hi->isBundle();
// 从编译器中读取并初始化Protocol
protocol_t **protolist = _getObjc2ProtocolList(hi, &count);
for (i = 0; i < count; i++) {
readProtocol(protolist[i], cls, protocol_map,
isPreoptimized, isBundle);
}
}
ts.log("IMAGE TIMES: discover protocols");
复制代码
#if !(defined(__x86_64__) && (TARGET_OS_OSX || TARGET_OS_SIMULATOR))
# define SUPPORT_FIXUP 0
#else
# define SUPPORT_FIXUP 1
#endif
#if SUPPORT_FIXUP
// Fix up old objc_msgSend_fixup call sites
for (EACH_HEADER) {
message_ref_t *refs = _getObjc2MessageRefs(hi, &count);
if (count == 0) continue;
if (PrintVtables) {
_objc_inform("VTABLES: repairing %zu unsupported vtable dispatch "
"call sites in %s", count, hi->fname());
}
for (i = 0; i < count; i++) {
fixupMessageRef(refs+i);
}
}
ts.log("IMAGE TIMES: fix up objc_msgSend_fixup");
#endif
复制代码
这段代码块通常状况下是不会执行的,其中fixupMessageRef
函数内部将经常使用的alloc、objc_msgSend等函数指针进行注册,并fix为新的函数指针。
// Realize non-lazy classes (for +load methods and static instances)
for (EACH_HEADER) {
classref_t *classlist =
_getObjc2NonlazyClassList(hi, &count);
for (i = 0; i < count; i++) {
Class cls = remapClass(classlist[i]);
// printf("non-lazy Class:%s\n",cls->mangledName());
if (!cls) continue;
// hack for class __ARCLite__, which didn't get this above #if TARGET_OS_SIMULATOR if (cls->cache._buckets == (void*)&_objc_empty_cache && (cls->cache._mask || cls->cache._occupied)) { cls->cache._mask = 0; cls->cache._occupied = 0; } if (cls->ISA()->cache._buckets == (void*)&_objc_empty_cache && (cls->ISA()->cache._mask || cls->ISA()->cache._occupied)) { cls->ISA()->cache._mask = 0; cls->ISA()->cache._occupied = 0; } #endif addClassTableEntry(cls); if (cls->isSwiftStable()) { if (cls->swiftMetadataInitializer()) { _objc_fatal("Swift class %s with a metadata initializer " "is not allowed to be non-lazy", cls->nameForLogging()); } // fixme also disallow relocatable classes // We can't disallow all Swift classes because of
// classes like Swift.__EmptyArrayStorage
}
// 实现全部非懒加载的类(实例化类对象的一些信息,例如rw)
realizeClassWithoutSwift(cls);
}
}
ts.log("IMAGE TIMES: realize non-lazy classes");
复制代码
所谓的非懒加载类就是实现了+load
类方法,在这段源码中对非懒加载类的bits
的data()
里面的rw
操做就是在realizeClassWithoutSwift
这个函数里面。
static Class realizeClassWithoutSwift(Class cls)
{
runtimeLock.assertLocked();
const class_ro_t *ro;
class_rw_t *rw;
Class supercls;
Class metacls;
bool isMeta;
if (!cls) return nil;
if (cls->isRealized()) return cls;
assert(cls == remapClass(cls));
// fixme verify class is not in an un-dlopened part of the shared cache?
ro = (const class_ro_t *)cls->data();
if (ro->flags & RO_FUTURE) {
// This was a future class. rw data is already allocated.
rw = cls->data();
ro = cls->data()->ro;
cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
} else {
// Normal class. Allocate writeable class data.
rw = (class_rw_t *)calloc(sizeof(class_rw_t), 1);
rw->ro = ro;
rw->flags = RW_REALIZED|RW_REALIZING;
cls->setData(rw);
}
isMeta = ro->flags & RO_META;
rw->version = isMeta ? 7 : 0; // old runtime went up to 6
// Choose an index for this class.
// Sets cls->instancesRequireRawIsa if indexes no more indexes are available
cls->chooseClassArrayIndex();
if (PrintConnecting) {
_objc_inform("CLASS: realizing class '%s'%s %p %p #%u %s%s",
cls->nameForLogging(), isMeta ? " (meta)" : "",
(void*)cls, ro, cls->classArrayIndex(),
cls->isSwiftStable() ? "(swift)" : "",
cls->isSwiftLegacy() ? "(pre-stable swift)" : "");
}
// Realize superclass and metaclass, if they aren't already. // This needs to be done after RW_REALIZED is set above, for root classes. // This needs to be done after class index is chosen, for root metaclasses. // This assumes that none of those classes have Swift contents, // or that Swift's initializers have already been called.
// fixme that assumption will be wrong if we add support
// for ObjC subclasses of Swift classes.
supercls = realizeClassWithoutSwift(remapClass(cls->superclass));
metacls = realizeClassWithoutSwift(remapClass(cls->ISA()));
#if SUPPORT_NONPOINTER_ISA
// Disable non-pointer isa for some classes and/or platforms.
// Set instancesRequireRawIsa.
bool instancesRequireRawIsa = cls->instancesRequireRawIsa();
bool rawIsaIsInherited = false;
static bool hackedDispatch = false;
if (DisableNonpointerIsa) {
// Non-pointer isa disabled by environment or app SDK version
instancesRequireRawIsa = true;
}
else if (!hackedDispatch && !(ro->flags & RO_META) &&
0 == strcmp(ro->name, "OS_object"))
{
// hack for libdispatch et al - isa also acts as vtable pointer
hackedDispatch = true;
instancesRequireRawIsa = true;
}
else if (supercls && supercls->superclass &&
supercls->instancesRequireRawIsa())
{
// This is also propagated by addSubclass()
// but nonpointer isa setup needs it earlier.
// Special case: instancesRequireRawIsa does not propagate
// from root class to root metaclass
instancesRequireRawIsa = true;
rawIsaIsInherited = true;
}
if (instancesRequireRawIsa) {
cls->setInstancesRequireRawIsa(rawIsaIsInherited);
}
// SUPPORT_NONPOINTER_ISA
#endif
// Update superclass and metaclass in case of remapping
cls->superclass = supercls;
cls->initClassIsa(metacls);
// Reconcile instance variable offsets / layout.
// This may reallocate class_ro_t, updating our ro variable.
if (supercls && !isMeta) reconcileInstanceVariables(cls, supercls, ro);
// Set fastInstanceSize if it wasn't set already. cls->setInstanceSize(ro->instanceSize); // Copy some flags from ro to rw if (ro->flags & RO_HAS_CXX_STRUCTORS) { cls->setHasCxxDtor(); if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) { cls->setHasCxxCtor(); } } // Propagate the associated objects forbidden flag from ro or from // the superclass. if ((ro->flags & RO_FORBIDS_ASSOCIATED_OBJECTS) || (supercls && supercls->forbidsAssociatedObjects())) { rw->flags |= RW_FORBIDS_ASSOCIATED_OBJECTS; } // Connect this class to its superclass's subclass lists
if (supercls) {
addSubclass(supercls, cls);
} else {
addRootClass(cls);
}
// Attach categories
methodizeClass(cls);
return cls;
}
复制代码
这部分的源码就是经过cls->data()
获得ro
,由于if (ro->flags & RO_FUTURE)
这个判断条件里面的代码通常状况下是不会执行的,因此只会执行else
里面的,在else
代码块里面只是初始化rw
,将其set到data()里面而已,此时rw
里面的method_array_t methods
,property_array_t properties
和protocol_array_t protocols
仍是没有值的。继续往下是
supercls = realizeClassWithoutSwift(remapClass(cls->superclass));
metacls = realizeClassWithoutSwift(remapClass(cls->ISA()));
复制代码
此时就是对父类
和元类
的类信息进行递归,此时就能够参考一下isa
的走位图就能够很明白此时的递归了。在下面的代码插入到继承链和isa
的走位链
// Update superclass and metaclass in case of remapping
cls->superclass = supercls;
cls->initClassIsa(metacls);
复制代码
而且递归的结束点是在函数开始的地方
if (!cls) return nil;
if (cls->isRealized()) return cls;
复制代码
由于最终的父类的根类是继承NSObject
,元类的根元类是也是继承NSObject
,而NSObject
的上一级终点是nil
。这里就很好地说明了这一切。
// Connect this class to its superclass's subclass lists if (supercls) { addSubclass(supercls, cls); } else { addRootClass(cls); } 复制代码
上面这段代码就是对父类和子类之间进行相似双向链表的形式进行关联。接着就是执行methodizeClass
函数了。
static void methodizeClass(Class cls)
{
runtimeLock.assertLocked();
bool isMeta = cls->isMetaClass();
auto rw = cls->data();
auto ro = rw->ro;
// Methodizing for the first time
if (PrintConnecting) {
_objc_inform("CLASS: methodizing class '%s' %s",
cls->nameForLogging(), isMeta ? "(meta)" : "");
}
// Install methods and properties that the class implements itself.
method_list_t *list = ro->baseMethods();
if (list) {
prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls));
rw->methods.attachLists(&list, 1);
}
property_list_t *proplist = ro->baseProperties;
if (proplist) {
rw->properties.attachLists(&proplist, 1);
}
protocol_list_t *protolist = ro->baseProtocols;
if (protolist) {
rw->protocols.attachLists(&protolist, 1);
}
// Root classes get bonus method implementations if they don't have // them already. These apply before category replacements. if (cls->isRootMetaclass()) { // root metaclass addMethod(cls, SEL_initialize, (IMP)&objc_noop_imp, "", NO); } // Attach categories. category_list *cats = unattachedCategoriesForClass(cls, true /*realizing*/); attachCategories(cls, cats, false /*don't flush caches*/);
if (PrintConnecting) {
if (cats) {
for (uint32_t i = 0; i < cats->count; i++) {
_objc_inform("CLASS: attached category %c%s(%s)",
isMeta ? '+' : '-',
cls->nameForLogging(), cats->list[i].cat->name);
}
}
}
if (cats) free(cats);
#if DEBUG
// Debug: sanity-check all SELs; log method list contents
for (const auto& meth : rw->methods) {
if (PrintConnecting) {
_objc_inform("METHOD %c[%s %s]", isMeta ? '+' : '-',
cls->nameForLogging(), sel_getName(meth.name));
}
assert(sel_registerName(sel_getName(meth.name)) == meth.name);
}
#endif
}
复制代码
在methodizeClass
函数中能够看到,此时从cls->data()
获取到的rw
里面的method_list_t
,property_list_t
和protocol_list_t
的值仍是空的。须要从rw
中的ro
获取到它们的值,并分别对rw
中的methods
,properties
和protocols
进行赋值,这个时候才是真正的对rw
里面的属性进行赋值。这些操做都是经过attachLists
函数来完成的。
void attachLists(List* const * addedLists, uint32_t addedCount) {
if (addedCount == 0) return;
if (hasArray()) {
// many lists -> many lists
uint32_t oldCount = array()->count;//10
uint32_t newCount = oldCount + addedCount;//4
setArray((array_t *)realloc(array(), array_t::byteSize(newCount)));
array()->count = newCount;// 10+4
memmove(array()->lists + addedCount, array()->lists,
oldCount * sizeof(array()->lists[0]));
memcpy(array()->lists, addedLists,
addedCount * sizeof(array()->lists[0]));
}
else if (!list && addedCount == 1) {
// 0 lists -> 1 list
list = addedLists[0];
}
else {
// 1 list -> many lists
List* oldList = list;
uint32_t oldCount = oldList ? 1 : 0;
uint32_t newCount = oldCount + addedCount;
setArray((array_t *)malloc(array_t::byteSize(newCount)));
array()->count = newCount;
if (oldList) array()->lists[addedCount] = oldList;
memcpy(array()->lists, addedLists,
addedCount * sizeof(array()->lists[0]));
}
}
复制代码
从源码能够看到,这个attachLists
函数中分别有多对多
,0对1
和1对多
这三种状况。
其中,memmove和memcpy函数做用都是拷贝必定长度的内存内容。当内存发生局部重叠时memmove函数可以保证拷贝结果的正确性,而memcpy则不能保证拷贝结果的正确性;当内存没有发生重叠的时候两个函数的结果是同样的。
memmove
函数将旧的数组列表添加到扩容后的数组中(memmove能够去掉重叠的内存),而后用memcpy
函数将须要添加的列表添加在旧的列表的前面。因此新添加的列表是在旧的列表的前面的。memcpy
函数进行拷贝。其中attachLists
函数除了在加载类处理方法,属性和协议的时候会被调用,还在添加方法addMethods
函数中,添加属性_class_addProperty
,添加协议class_addProtocol
和分类的加载attachCategories
中都会被调用。
懒加载类和非懒加载类的主要区别就是是否实现了+load
方法,上面介绍了非懒加载类,那么懒加载类是怎么实现的呢?其实懒加载类就是在调用的时候才实现的,那么这就是在该类第一次调用方法的时候会被初始化加载进来,这个时候就须要去到lookUpImpOrForward
这个函数里面了。若是想了解这个函数的能够看一下iOS的OC的方法的查找原理 这篇文章的介绍。其中有这么一段源码
if (!cls->isRealized()) {
cls = realizeClassMaybeSwiftAndLeaveLocked(cls, runtimeLock);
// runtimeLock may have been dropped but is now locked again
}
================================
static Class
realizeClassMaybeSwiftAndLeaveLocked(Class cls, mutex_t& lock)
{
return realizeClassMaybeSwiftMaybeRelock(cls, lock, true);
}
static Class
realizeClassMaybeSwiftMaybeRelock(Class cls, mutex_t& lock, bool leaveLocked)
{
lock.assertLocked();
if (!cls->isSwiftStable_ButAllowLegacyForNow()) {
// Non-Swift class. Realize it now with the lock still held.
// fixme wrong in the future for objc subclasses of swift classes
realizeClassWithoutSwift(cls);
if (!leaveLocked) lock.unlock();
} else {
// Swift class. We need to drop locks and call the Swift
// runtime to initialize it.
lock.unlock();
cls = realizeSwiftClass(cls);
assert(cls->isRealized()); // callback must have provoked realization
if (leaveLocked) lock.lock();
}
return cls;
}
复制代码
从源码中能够看到,在方法查找的过程当中,若是当前的cls
没有实现的话,就会执行realizeClassMaybeSwiftAndLeaveLocked
函数,最终会执行到realizeClassMaybeSwiftMaybeRelock
函数中。在这个函数中分别有Non-Swift class
和Swift class
的判断,当前的是OC
的类,最终仍是会执行到realizeClassWithoutSwift
函数,而这个函数在上面也介绍了是对rw和ro
的操做的。
经过上面的一系列源码的分析了类的加载
整个过程,接下来总结一下:
dyld
加载过程当中,从dyld
过分到objc
是在_objc_init
函数中_dyld_objc_notify_register
函数回调回来的。_read_images
函数读取镜像
文件的内容到内存中,在而且在这个过程当中若是是初次进入会分别初始化gdb_objc_realized_classes
和allocatedClasses
两张哈希表,其中加载全部的类在gdb_objc_realized_classes
表中,分配内存的类也会在allocatedClasses
表中。SEL
都注册到namedSelectors
表中。Protocol
注册到protocol_map
表。Protocol
作重映射。rw
和ro
操做。Category
,包括Class
和MetaClass
。