objc-init分析
分别调用了很多方法分别是:
environ_init(): 读取影响运⾏时的环境变量。如果需要,还可以打印环境变量帮助。tls_init():关于线程key的绑定 - ⽐如每线程数据的析构函数static_init():运⾏C ++静态构造函数。在dyld调⽤我们的静态构造函数之前,libc 会调⽤_objc_init(),因此我们必须⾃⼰做lock_init(): 没有重写,采⽤C++的特性exception_init()初始化libobjc的异常处理系统cache_init(): 缓存条件初始化runtime_init(): runtime运⾏时环境初始化,⾥⾯主要是:unattachedCategories,allocatedClasses 后⾯会分析_imp_implementationWithBlock_init:启动回调机制。通常这不会做什么,因为所有的初始化都 是惰性的,但是对于某些进程,我们会迫不及待地加载trampolines dylib。
environ_init(); 读取影响运行时的环境变量。如果需要,还可以打印环境变量帮助。
-
- 进入
void environ_init(void)源码查看
- 进入
void environ_init(void)
{
...
//这段代码是下面代码的复制,同时删除判断。运行后。
for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
const option_t *opt = &Settings[i];
_objc_inform("%s: %s", opt->env, opt->help);
_objc_inform("%s is set", opt->env);
}
...
// Print OBJC_HELP and OBJC_PRINT_OPTIONS output.
if (PrintHelp || PrintOptions) {
if (PrintHelp) {
_objc_inform("Objective-C runtime debugging. Set variable=YES to enable.");
_objc_inform("OBJC_HELP: describe available environment variables");
if (PrintOptions) {
_objc_inform("OBJC_HELP is set");
}
_objc_inform("OBJC_PRINT_OPTIONS: list which options are set");
}
if (PrintOptions) {
_objc_inform("OBJC_PRINT_OPTIONS is set");
}
for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
const option_t *opt = &Settings[i];
if (PrintHelp) _objc_inform("%s: %s", opt->env, opt->help);
if (PrintOptions && *opt->var) _objc_inform("%s is set", opt->env);
}
}
...
}
- 会有很多的数据打印,同时有这个 OBJC_DISABLE_NONPOINTER_ISA is set
- OBJC_DISABLE_NONPOINTER_ISA is set 这个就是isa-联合体中第一位的设置。
- 测试一下这个设置与不设置的差别
- 1.创建一个对象,打上断点
- 2.x/4gx p 打印对象的内存地址,以8字节的形式输出4段
- 3.p/t 0x011d8001000082d1 以2进制的输出p对象的isa的首地址
- 修改环境变量
- 运行打印
- 发现没有OBJC_DISABLE_NONPOINTER_ISA is set打印了同时 p的isa的末尾也是0,说明这个isa-已经是一个纯的isa,不再是联合体了
- 现在来测试下这个JC_PRINT_LOAD_METHODS,勾选。
- load方法浪费性能。
- 打印出哪些类中调用了load方法。
- 就可以对这个类进行优化。
- 现在发现原来在这个环境变量设置下能完成很多事情,现在我想知道其他的变量设置,但是有不知道是什么时。
- 1.打开终端
- 2.第一个指令
export OBJC_HELP=1 - 3.第二个指令
/Applications/Safari.app/Contents/MacOS/Safari - 回车后会有很多的打印环境变量设置和注释
Objective-C runtime debugging. Set variable=YES to enable.
objc[1591]: OBJC_HELP: describe available environment variables
objc[1591]: OBJC_PRINT_OPTIONS: list which options are set
objc[1591]: OBJC_PRINT_IMAGES: log image and library names as they are loaded
objc[1591]: OBJC_PRINT_IMAGE_TIMES: measure duration of image loading steps
objc[1591]: OBJC_PRINT_LOAD_METHODS: log calls to class and category +load methods
objc[1591]: OBJC_PRINT_INITIALIZE_METHODS: log calls to class +initialize methods
objc[1591]: OBJC_PRINT_RESOLVED_METHODS: log methods created by +resolveClassMethod: and +resolveInstanceMethod:
objc[1591]: OBJC_PRINT_CLASS_SETUP: log progress of class and category setup
objc[1591]: OBJC_PRINT_PROTOCOL_SETUP: log progress of protocol setup
objc[1591]: OBJC_PRINT_IVAR_SETUP: log processing of non-fragile ivars
objc[1591]: OBJC_PRINT_VTABLE_SETUP: log processing of class vtables
objc[1591]: OBJC_PRINT_VTABLE_IMAGES: print vtable images showing overridden methods
objc[1591]: OBJC_PRINT_CACHE_SETUP: log processing of method caches
objc[1591]: OBJC_PRINT_FUTURE_CLASSES: log use of future classes for toll-free bridging
objc[1591]: OBJC_PRINT_PREOPTIMIZATION: log preoptimization courtesy of dyld shared cache
objc[1591]: OBJC_PRINT_CXX_CTORS: log calls to C++ ctors and dtors for instance variables
objc[1591]: OBJC_PRINT_EXCEPTIONS: log exception handling
objc[1591]: OBJC_PRINT_EXCEPTION_THROW: log backtrace of every objc_exception_throw()
objc[1591]: OBJC_PRINT_ALT_HANDLERS: log processing of exception alt handlers
objc[1591]: OBJC_PRINT_REPLACED_METHODS: log methods replaced by category implementations
objc[1591]: OBJC_PRINT_DEPRECATION_WARNINGS: warn about calls to deprecated runtime functions
objc[1591]: OBJC_PRINT_POOL_HIGHWATER: log high-water marks for autorelease pools
objc[1591]: OBJC_PRINT_CUSTOM_CORE: log classes with custom core methods
objc[1591]: OBJC_PRINT_CUSTOM_RR: log classes with custom retain/release methods
objc[1591]: OBJC_PRINT_CUSTOM_AWZ: log classes with custom allocWithZone methods
objc[1591]: OBJC_PRINT_RAW_ISA: log classes that require raw pointer isa fields
objc[1591]: OBJC_DEBUG_UNLOAD: warn about poorly-behaving bundles when unloaded
objc[1591]: OBJC_DEBUG_FRAGILE_SUPERCLASSES: warn about subclasses that may have been broken by subsequent changes to superclasses
objc[1591]: OBJC_DEBUG_NIL_SYNC: warn about @synchronized(nil), which does no synchronization
objc[1591]: OBJC_DEBUG_NONFRAGILE_IVARS: capriciously rearrange non-fragile ivars
objc[1591]: OBJC_DEBUG_ALT_HANDLERS: record more info about bad alt handler use
objc[1591]: OBJC_DEBUG_MISSING_POOLS: warn about autorelease with no pool in place, which may be a leak
objc[1591]: OBJC_DEBUG_POOL_ALLOCATION: halt when autorelease pools are popped out of order, and allow heap debuggers to track autorelease pools
objc[1591]: OBJC_DEBUG_DUPLICATE_CLASSES: halt when multiple classes with the same name are present
objc[1591]: OBJC_DEBUG_DONT_CRASH: halt the process by exiting instead of crashing
objc[1591]: OBJC_DEBUG_POOL_DEPTH: log fault when at least a set number of autorelease pages has been allocated
objc[1591]: OBJC_DEBUG_SCRIBBLE_CACHES: scribble the IMPs in freed method caches
objc[1591]: OBJC_DISABLE_VTABLES: disable vtable dispatch
objc[1591]: OBJC_DISABLE_PREOPTIMIZATION: disable preoptimization courtesy of dyld shared cache
objc[1591]: OBJC_DISABLE_TAGGED_POINTERS: disable tagged pointer optimization of NSNumber et al.
objc[1591]: OBJC_DISABLE_TAG_OBFUSCATION: disable obfuscation of tagged pointers
objc[1591]: OBJC_DISABLE_NONPOINTER_ISA: disable non-pointer isa fields
objc[1591]: OBJC_DISABLE_INITIALIZE_FORK_SAFETY: disable safety checks for +initialize after fork
objc[1591]: OBJC_DISABLE_FAULTS: disable os faults
objc[1591]: OBJC_DISABLE_PREOPTIMIZED_CACHES: disable preoptimized caches
objc[1591]: OBJC_DISABLE_AUTORELEASE_COALESCING: disable coalescing of autorelease pool pointers
objc[1591]: OBJC_DISABLE_AUTORELEASE_COALESCING_LRU: disable coalescing of autorelease pool pointers using look back N strategy
| 变量名 | 介绍 | 备注 |
|---|---|---|
| OBJC_PRINT_OPTIONS | list which options are set | 输出OBJC已设置的选项 |
| OBJC_PRINT_IMAGES | log image and library names as they are loaded | 输出已load的image信息 |
| OBJC_PRINT_LOAD_METHODS | log calls to class and category +load methods | 打印 Class 及 Category 的 + (void)load 方法的调用信息 |
| OBJC_PRINT_INITIALIZE_METHODS | log calls to class +initialize methods | 打印 Class 的 + (void)initialize 的调用信息 |
| OBJC_PRINT_RESOLVED_METHODS | log methods created by +resolveClassMethod and +resolveInstanceMethod: | 打印通过 +resolveClassMethod: 或 +resolveInstanceMethod: 生成的类方法 |
| OBJC_PRINT_CLASS_SETUP | log progress of class and category setup | 打印 Class 及 Category 的设置过程 |
| OBJC_PRINT_PROTOCOL_SETUP | log progress of protocol setup | 打印 Protocol 的设置过程 |
| OBJC_PRINT_IVAR_SETUP | log processing of non-fragile ivars | 打印 Ivar 的设置过程 |
| OBJC_PRINT_VTABLE_SETUP | log processing of class vtables | 打印 vtable 的设置过程 |
| OBJC_PRINT_VTABLE_IMAGES | print vtable images showing overridden methods | 打印 vtable 被覆盖的方法 |
| OBJC_PRINT_CACHE_SETUP | log processing of method caches | 打印方法缓存的设置过程 |
| OBJC_PRINT_FUTURE_CLASSES | log use of future classes for toll-free bridging | 打印从 CFType 无缝转换到 NSObject 将要使用的类(如 CFArrayRef 到 NSArray * ) |
| OBJC_PRINT_GC | log some GC operations | 打印一些垃圾回收操作 |
| OBJC_PRINT_PREOPTIMIZATION | log preoptimization courtesy of dyld shared cache | 打印 dyld 共享缓存优化前的问候语 |
| OBJC_PRINT_CXX_CTORS | log calls to C++ ctors and dtors for instance variables | 打印类实例中的 C++ 对象的构造与析构调用 |
| OBJC_PRINT_EXCEPTIONS | log exception handling | 打印异常处理 |
| OBJC_PRINT_EXCEPTION_THROW | log backtrace of every objc_exception_throw() | 打印所有异常抛出时的 Backtrace |
| OBJC_PRINT_ALT_HANDLERS | log processing of exception alt handlers | 打印 alt 操作异常处理 |
| OBJC_PRINT_REPLACED_METHODS | log methods replaced by category implementations | 打印被 Category 替换的方法 |
| OBJC_PRINT_DEPRECATION_WARNINGS | warn about calls to deprecated runtime functions | 打印所有过时的方法调用 |
| OBJC_PRINT_POOL_HIGHWATER | log high-water marks for autorelease pools | 打印 autoreleasepool 高水位警告 |
| OBJC_PRINT_CUSTOM_RR | log classes with un-optimized custom retain/release methods | 打印含有未优化的自定义 retain/release 方法的类 |
| OBJC_PRINT_CUSTOM_AWZ | log classes with un-optimized custom allocWithZone methods | 打印含有未优化的自定义 allocWithZone 方法的类 |
| OBJC_PRINT_RAW_ISA | log classes that require raw pointer isa fields | 打印需要访问原始 isa 指针的类 |
| OBJC_DEBUG_UNLOAD | warn about poorly-behaving bundles when unloaded | 卸载有不良行为的 Bundle 时打印警告 |
| OBJC_DEBUG_FRAGILE_SUPERCLASSES | warn about subclasses that may have been broken by subsequent changes to superclasses | 当子类可能被对父类的修改破坏时打印警告 |
| OBJC_DEBUG_FINALIZERS | warn about classes that implement -dealloc but not -finalize | 警告实现了 -dealloc 却没有实现 -finalize 的类 |
| OBJC_DEBUG_NIL_SYNC | warn about @synchronized(nil), which does no synchronization | 警告 @synchronized(nil) 调用,这种情况不会加锁 |
| OBJC_DEBUG_NONFRAGILE_IVARS | capriciously rearrange non-fragile ivars | 打印突发地重新布置 non-fragile ivars 的行为 |
| OBJC_DEBUG_ALT_HANDLERS | record more info about bad alt handler use | 记录更多的 alt 操作错误信息 |
| OBJC_DEBUG_MISSING_POOLS | warn about autorelease with no pool in place, which may be a leak | 警告没有 pool 的情况下使用 autorelease,可能内存泄漏 |
| OBJC_DEBUG_DUPLICATE_CLASSES | halt when multiple classes with the same name are present | 当出现类重名时停机 |
| OBJC_USE_INTERNAL_ZONE | allocate runtime data in a dedicated malloc zone | 在一个专用的 malloc 区分配运行时数据 |
| OBJC_DISABLE_GC | force GC OFF, even if the executable wants it on | 强行关闭自动垃圾回收,即使可执行文件需要垃圾回收 |
| OBJC_DISABLE_VTABLES | disable vtable dispatch | 关闭 vtable 分发 |
| OBJC_DISABLE_PREOPTIMIZATION | disable preoptimization courtesy of dyld shared cache | 关闭 dyld 共享缓存优化前的问候语 |
| OBJC_DISABLE_TAGGED_POINTERS | disable tagged pointer optimization of NSNumber et al. | 关闭 NSNumber 等的 tagged pointer 优化 |
| OBJC_DISABLE_NONPOINTER_ISA | disable non-pointer isa fields | 关闭 non-pointer isa 字段的访问 |
- 上述的指令用于调试(了解)
tls_init(); 关于线程key的绑定,比如每条线程数据的析构函数
- 如每条线程的析构函数(这里先不做说明)
static_init();
- 运行C++静态析构函数。在dyld调用我们的静态构造函数之前,
linc会调用_objc_init()因此我们必须自己做
/***********************************************************************
* static_init
* Run C++ static constructor functions.
* libc calls _objc_init() before dyld would call our static constructors,
* so we have to do it ourselves.
* static_init
* 运行c++静态构造函数。
* libc在dyld调用静态构造函数之前调用_objc_init(),
* 所以我们必须自己做。
dyldy 会自动调用我们的库的全局静态函数,如: __attribute__((constructor)) static void libSystem_initializer
static_init(),我们自己去调用,在_objc_init()调用之后我们自己去调用自己库中的dyly的静态方法。
**********************************************************************/
static void static_init()
{
size_t count;
auto inits = getLibobjcInitializers(&_mh_dylib_header, &count);
for (size_t i = 0; i < count; i++) {
inits[i]();
}
auto offsets = getLibobjcInitializerOffsets(&_mh_dylib_header, &count);
for (size_t i = 0; i < count; i++) {
UnsignedInitializer init(offsets[i]);
init();
}
}
- 主动调用了全局静态函数,即
__attribute__((constructor)) void objcFunc(){
printf("来了 : %s \n",__func__);
}
这样写法的函数会被主动调用,然后
__attribute__((constructor))
static void
libSystem_initializer(int argc,
const char* argv[],
const char* envp[],
const char* apple[],
const struct ProgramVars* vars){
}
-
就主动调用了这个方法。
-
这样写法函数写在objc库中,才能保证 在调用
_dyld_objc_notify_register(&map_images, load_images, unmap_image);函数之前,保证所有的全局静态函数的完成调用。
runtime_init();
- runtime运⾏时环境初始化,⾥⾯主要是:unattachedCategories,allocatedClasses 后⾯会分析
- 初始化两张表
unattachedCategories,allocatedClasses
exception_init(); 初始化lib_objc的异常处理系统
- 异常的监听初始化(暂时忽略)
/***********************************************************************
* exception_init
* Initialize libobjc's exception handling system.
* Called by map_images().
* exception_init
初始化libobjc的异常处理系统。
*由map_images()调用。
**********************************************************************/
void exception_init(void)
{
old_terminate = std::set_terminate(&_objc_terminate);
}
cache_init() 缓存条件初始化
_imp_implementationWithBlock_init :启动回调机制。通常这不会做什么,因为所有的初始化都是惰性的,但是对于某些进程,我们会迫不及待的加载trampolines dylib
分
- 重点
_dyld_objc_notify_register(&map_images, load_images, unmap_image); 分析
map_images()dyld将image镜像文件加载到内存中会调用该函数。load_images()dyld初始化所有的image镜像文件文件会调用。unmap_image:将image镜像文件移除时会调用。
load_images方法其实就是调用load方法,map_image方法,&map_images是指针传递,指向是同一块实现的地址,如果有什么变化就可以第一时间知道。在dyld中sNotifyObjCMapped调用的地方是在notifyBatchPartial方法中,而notifyBatchPartial方法是在registerObjCNotifiers中调用,在objc初始化注册通知时就调用了,所以是先调用map_images后调用load_images这么个函数执行顺序。
- &map_images 地址值作为参数,即指针传递,数据同步进行变化。map_images 函数是一个不断递归的函数
map_images 函数分析
/***********************************************************************
* map_images
* Process the given images which are being mapped in by dyld.
* Calls ABI-agnostic code after taking ABI-specific locks.
*
* Locking: write-locks runtimeLock
* map_images
*处理由dyld映射的给定图像。映射镜像文件
*在获取abi特定的锁后调用abi不可知代码。
*
*锁:写锁runtimeLock
**********************************************************************/
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);
}
- map_images_nolock 由于代码量过多非重点部分省略 ...
map_images_nolock(unsigned mhCount, const char * const mhPaths[],
const struct mach_header * const mhdrs[]){
...
//重点进入这个循环调用中,开始读取镜像文件
if (hCount > 0) {
_read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
}
...
}
read_images函数分析 主要完成的是以下的几个功能
- 1、条件控制进行一次的加载
- 2、修复预编译阶段‘@selector’的混乱问题
- 3、错误混乱的类处理
- 4、修复重映射一些没有被镜像文件加载进来的类
- 5、修复一些消息
- 6、当我们类里面有协议的时候:readProtocol
- 7、修复没有被加载的协议
- 8、分类处理
- 9、类的加载处理
- 10、没有被处理的类优化那些被侵犯的类
1.条件控制进行一次的加载 doneOnce
if (!doneOnce) {
doneOnce = YES;
launchTime = YES;
...
...
// namedClasses
// Preoptimized classes don't go in this table.
// 4/3 is NXMapTable's load factor
// objc::unattachedCategories.init(32);
// objc::allocatedClasses.init(); //(生成一张被开辟alloc的表)
int namedClassesSize =
(isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;
//创建了一个表(总表关于类名的表,不管是否有被实现)
gdb_objc_realized_classes =
NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);
ts.log("IMAGE TIMES: first time tasks");
}
- 加载一次下次就不会再次进入判断,第一次进来主要创建表
gbd_objc_realized_classes,这是一张关于所有类的不管是否有没有被实现都存放进入。是一张总表。 - 主要作用是生成一张关于全部类名的总表,不管这个类是否有被实现
alloc init allocatedClass.init(),生成一张已经被开辟内存的表。
2.修复预编译阶段‘@selector’的混乱问题
// Fix up @selector references
// sel 名字 + 地址
static size_t UnfixedSelectors;
{
mutex_locker_t lock(selLock);
for (EACH_HEADER) {
if (hi->hasPreoptimizedSelectors()) 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 sel = sel_registerNameNoLock(name, isBundle);
if (sels[i] != sel) {
sels[i] = sel;
}
}
}
}
- 不同的类中可能存在相同的方法,但是方法名相当地址是不同的。
- 如:两个方法名相同,但是地址不同,需要进行局部处理。类的地址重定向。
sels[i]是_getObjc2SelectorRefs是从MachO里面获取的,MachO有相对位移地址和偏移地址,sel是sel_registerNameNoLock从dyld里面获取,dyld是链接整个程序的,所以以dyld的为准。因为方法是存放在类中,每个类中的位置是不一样的,所以方法的地址也就不一样,那么就必须对那些混乱的方法进行修复处理。
3、错误混乱的类处理
// Discover classes. Fix up unresolved future classes. Mark bundle classes.
//发现类。修复未解决的未来类。马克包类。
bool hasDyldRoots = dyld_shared_cache_some_image_overridden();
for (EACH_HEADER) {
if (! mustReadClasses(hi, hasDyldRoots)) {
// Image is sufficiently optimized that we need not call readClass()
continue;
}
classref_t const *classlist = _getObjc2ClassList(hi, &count);
bool headerIsBundle = hi->isBundle();
bool headerIsPreoptimized = hi->hasPreoptimizedClasses();
for (i = 0; i < count; i++) {
Class cls = (Class)classlist[i];
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");
- 清除没有清理干净的类
- 类的地址读取加载。
- readClass方法的作用:把类名和地址关联起来。
readClass 类的读取 现在开始研究我们自己写的类是如何加载的
/***********************************************************************
* readClass
* Read a class and metaclass as written by a compiler.
* Returns the new class pointer. This could be:
* - cls
* - nil (cls has a missing weak-linked superclass)
* - something else (space for this class was reserved by a future class)
*
* Note that all work performed by this function is preflighted by
* mustReadClasses(). Do not change this function without updating that one.
*
* Locking: runtimeLock acquired by map_images or objc_readClassPair
**********************************************************************/
Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized)
{
//获取类名
const char *mangledName = cls->nonlazyMangledName();
const char *LGPersonName = "LGPerson";
if (strcmp(mangledName, LGPersonName) == 0) {
// 普通写得类 他是如何
printf("%s -KC: 要研究的: - %s\n",__func__,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->setSuperclass(nil);
return nil;
}
cls->fixupBackwardDeployingStableSwift();
Class replacing = nil;
if (mangledName != nullptr) {
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));
// Manually set address-discriminated ptrauthed fields
// so that newCls gets the correct signatures.
newCls->setSuperclass(cls->getSuperclass());
newCls->initIsa(cls->getIsa());
rw->set_ro((class_ro_t *)newCls->data());
newCls->setData(rw);
freeIfMutable((char *)old_ro->getName());
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(mangledName == nullptr || getClassExceptSomeSwift(mangledName));
} else {
if (mangledName) { //some Swift generic classes can lazily generate their names
addNamedClass(cls, mangledName, replacing);
} else {
Class meta = cls->ISA();
const class_ro_t *metaRO = meta->bits.safe_ro();
ASSERT(metaRO->getNonMetaclass() && "Metaclass with lazy name must have a pointer to the corresponding nonmetaclass.");
ASSERT(metaRO->getNonMetaclass() == cls && "Metaclass nonmetaclass pointer must equal the original class.");
}
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;
}
- 1.在自己写的类创建之前断点。
- 2.写上语句判断打印并断点
const char *LGPersonName = "LGPerson";
if (strcmp(mangledName, LGPersonName) == 0) {
// 普通写得类 他是如何
printf("%s -KC: 要研究的: - %s\n",__func__,mangledName);
}
- 3.打印信息提示
加载类流程
- 1.
readClass-> 这里并没有对类的ro,rw的赋值 nonlazyMangleName 获取类型 - 2.
addNameClass(cls,magleName,replacing)-> 将类型和地址关联起来 - 3.
addClassTableEntry(cls),在这里加载类以及元类inset(cls)和addMeta - 这里主要完成的是将类加入到表中,将这个类名的类以及元类插入到另一张哈希表中。这张表中的类都是初始化过的类
realizeClassWithoutSwift(cls, nil); 的分析流程
- methodelizeClass() 相关方法的排序
- prepareMehodList 对ro中的baseMethods()方法 方法名写入+排序
懒加载与非懒加载类 :
- 当前类是否实现load方法,load方法会让一个类从懒加载类成为一个非懒加载类,懒加载类的好处是能够按需分配内存,节约内存。
- 1.懒加载类情况 : 数据加载推迟到第一次消息的时候
- lookUpImpOrForward
- realizeClassMaybeSwiftMaybeRelock
- realizeClassWithoutSwift
- methodizeClass
- 2.非懒加载类情况 : map_images的时候加载了所有类数据
- readClass
- _getObjc2NonlazyClassList
- realizeClassWithoutSwift
- methodizeClass