小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
1.主类方法和分类方法的调用顺序?
1.1 普通方法
普通方法,包括initialize
,优先分类中的方法调用
因为分类的方法是在类realize
之后attach
进去的,所以插在前面
1.2 load方法
load方法,优先主类,然后分类
因为类的初始化,优先主类,读取ro
。然后分类初始化,读取rwe
1.3 多分类
多个分类之间,看文件的编译顺序。load
方法,先编译的分类先执行。同名方法,最后编译的分类中的方法会执行
2. load、initialize、cxx的调用顺序?
load
方法和cxx
函数,在程序启动时自动调用,调用顺序:load
-> cxx
-> main
对于相同镜像文件,load
方法一定在cxx
函数之前
不同镜像文件的调用顺序:系统库优先 -> 动态库 -> 主程序
initialize
方法,属于懒加载方法,在对象首次消息发送时调用
objc
中的cxx
函数,它会在_objc_init
函数中,调用static_init
函数,执行C++
静态构造函数
3. 能否在运行时对编译后的类添加实例变量?
不能,因为编译后的实例变量存储在ro
中,一旦编译完成,内存结构就完全确定了,无法修改。可以对编译后的类添加属性和方法。
4.能否对运行时创建的类添加实例变量?
可以对运行时创建的类添加实例变量,使用objc_allocateClassPair
创建类,只要在objc_registerClassPair
注册之前,可添加实例变量。一旦注册后,无法添加实例变量。
使用class_addIvar
添加实例变量,添加钱进行flags & RW_CONSTRUCTING
的条件判断
BOOL class_addIvar(Class cls, const char *name, size_t size, uint8_t alignment, const char *type)
{
...
// No class variables
if (cls->isMetaClass()) {
return NO;
}
// Can only add ivars to in-construction classes.
if (!(cls->data()->flags & RW_CONSTRUCTING)) {
return NO;
}
...
}
调用objc_registerClassPair
函数,会对flags
进行标记
void objc_registerClassPair(Class cls)
{
...
// Clear "under construction" bit, set "done constructing" bit
cls->ISA()->changeInfo(RW_CONSTRUCTED, RW_CONSTRUCTING | RW_REALIZING);
cls->changeInfo(RW_CONSTRUCTED, RW_CONSTRUCTING | RW_REALIZING);
...
}
5.Runtime是如何实现weak的,为什么可以自动置nil?
- 1.通过
SideTable
找到我们的weak_table
- 2.
weak_table
根据referent
找到或者创建weak_entry_t
- 3.然后
append_referrer(entry, referrer)
将我的新弱引用的对象加进去entry
- 4.最后
weak_entry_insert
把entry
加入到我们的weak_table