问题先行
1、initalize
和load
的区别是什么?
2、如下代码输出结果是?
@implementation ASSon
- (instancetype)init {
if (self == [super init]) {
NSLog(@"[self class]=%@,[super class]=%@,",[self class],[super class]);
}
return self;
}
@end
3、编译后的类能否添加成员变量?运行时创建的类能否添加成员变量?
4、如下代码输出结果是?
[[[ASSon alloc]init] faction1];
5、关联对象需要自己进行释放吗?
initalize分析
官方描述
Initializes the class before it receives its first message
在这个类接收第一条消息之前调用
根据这个重要的注释,我们看下消息发送的流程方法路径,不难发现在判断类是否初始化即初始化的相关逻辑中存在initalize
相关。
相关路径如下
lookUpImpOrForward
->realizeAndInitializeIfNeeded_locked
->initializeAndLeaveLocked
->initializeAndMaybeRelock
->initializeNonMetaClass
->callInitialize
NEVER_INLINE
IMP lookUpImpOrForward(id inst, SEL sel, Class cls, int behavior)
{
const IMP forward_imp = (IMP)_objc_msgForward_impcache;
IMP imp = nil;
Class curClass;
runtimeLock.assertUnlocked();
/// 代码省略......
checkIsKnownClass(cls);
/// 判断类是否实现,如果没有是实现,需要先实现。此时的目的是为了确定父类链,方法后续的循环
cls = realizeAndInitializeIfNeeded_locked(inst, cls, behavior & LOOKUP_INITIALIZE);
// runtimeLock may have been dropped but is now locked again
runtimeLock.assertLocked();
curClass = cls;
/// 代码省略......
return imp;
}
static Class
realizeAndInitializeIfNeeded_locked(id inst, Class cls, bool initialize)
{
runtimeLock.assertLocked();
if (slowpath(!cls->isRealized())) {
cls = realizeClassMaybeSwiftAndLeaveLocked(cls, runtimeLock);
// runtimeLock may have been dropped but is now locked again
}
/// 判断类是否初始化,如果没有需要先初始化
if (slowpath(initialize && !cls->isInitialized())) {
cls = initializeAndLeaveLocked(cls, inst, runtimeLock);
// runtimeLock may have been dropped but is now locked again
// If sel == initialize, class_initialize will send +initialize and
// then the messenger will send +initialize again after this
// procedure finishes. Of course, if this is not being called
// from the messenger then it won't happen. 2778172
}
return cls;
}
// Locking: caller must hold runtimeLock; this may drop and re-acquire it
static Class initializeAndLeaveLocked(Class cls, id obj, mutex_t& lock)
{
return initializeAndMaybeRelock(cls, obj, lock, true);
}
static Class initializeAndMaybeRelock(Class cls, id inst,
mutex_t& lock, bool leaveLocked)
{
lock.assertLocked();
ASSERT(cls->isRealized());
if (cls->isInitialized()) {
if (!leaveLocked) lock.unlock();
return cls;
}
// Find the non-meta class for cls, if it is not already one.
// The +initialize message is sent to the non-meta class object.
Class nonmeta = getMaybeUnrealizedNonMetaClass(cls, inst);
// Realize the non-meta class if necessary.
if (nonmeta->isRealized()) {
// nonmeta is cls, which was already realized
// OR nonmeta is distinct, but is already realized
// - nothing else to do
lock.unlock();
} else {
nonmeta = realizeClassMaybeSwiftAndUnlock(nonmeta, lock);
// runtimeLock is now unlocked
// fixme Swift can't relocate the class today,
// but someday it will:
cls = object_getClass(nonmeta);
}
// runtimeLock is now unlocked, for +initialize dispatch
ASSERT(nonmeta->isRealized());
///
initializeNonMetaClass(nonmeta);
if (leaveLocked) runtimeLock.lock();
return cls;
}
void initializeNonMetaClass(Class cls)
{
ASSERT(!cls->isMetaClass());
Class supercls;
bool reallyInitialize = NO;
// Make sure super is done initializing BEFORE beginning to initialize cls.
// See note about deadlock above.
supercls = cls->getSuperclass();
if (supercls && !supercls->isInitialized()) {
/// 递归调用父类
initializeNonMetaClass(supercls);
}
/// 代码省略......
{
/// 消息发送initialize
callInitialize(cls);
/// 代码省略......
return;
}
/// 代码省略......
}
void callInitialize(Class cls)
{
((void(*)(Class, SEL))objc_msgSend)(cls, @selector(initialize));
asm("");
}
initialize
在类或者其子类的第一个方法被调用前(发送消息前)调用- 父类的
initialize
方法会比子类先执行 - 当子类未实现
initialize
方法时,会调用父类initialize
方法;子类实现initialize
方法时,会覆盖父类initialize
方法 - 当有多个分类都实现了
initialize
方法,会覆盖类中的方法,只执行一个(会执行最后被加载到内存中的分类的方法)
[self class]、[super class]分析
通过clang
编译出cpp
文件,然后分析核心代码
// @implementation ASSon
static instancetype _I_ASSon_init(ASSon * self, SEL _cmd) {
if (self == ((ASSon *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("ASSon"))}, sel_registerName("init"))) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_nm_y1t1syks0yj_jrzr73yc4qp00000gn_T_ASSon_b9cdb4_mi_0,((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class")),((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("ASSon"))}, sel_registerName("class")));
}
return self;
}
// @end
struct __rw_objc_super {
struct objc_object *object;
struct objc_object *superClass;
__rw_objc_super(struct objc_object *o, struct objc_object *s) : object(o), superClass(s) {}
};
[self class]
[self class]
是通过objc_msgSend
进行消息发送,消息接收者是self
,方法编号class
- (Class)class {
return object_getClass(self);
}
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
通过class
的objc
源码可知是获取对象的isa
,当前的对象是ASSon
其isa
就是ASSon
,所以[self class]
打印的是ASSon
。
[super class]
[super class]
则是通过objc_msgSendSuper
进行消息发送,消息接受者为__rw_objc_super
结构类型参数,方法编号class
注意由于
objc
会存在一些编译优化的操作,我们通过汇编看下是否有进行objc_msgSendSuper
方法的编译优化。发现最终是调用
objc_msgSendSuper2
方法。
// objc_msgSendSuper2() takes the current search class, not its superclass.
OBJC_EXPORT id _Nullable
objc_msgSendSuper2(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
OBJC_AVAILABLE(10.6, 2.0, 9.0, 1.0, 2.0);
objc_msgSendSuper2
源码如上可以看出第一个参数为objc_super
,由此可知.cpp
文件中__rw_objc_super
其实是一个中间结构体。
/// Specifies the superclass of an instance.
struct objc_super {
/// Specifies an instance of a class.
__unsafe_unretained _Nonnull id receiver;
/// Specifies the particular superclass of the instance to message.
#if !defined(__cplusplus) && !__OBJC2__
/* For compatibility with old objc-runtime.h header */
__unsafe_unretained _Nonnull Class class;
#else
__unsafe_unretained _Nonnull Class super_class;
#endif
/* super_class is the first class to search */
};
通过objc_super
的源码可知,当前消息的接收者为参数receiver
,而receiver
等于传入self
,因此[super class]
其中的self
是init
后的实例对象,其isa
即消息接收者是ASSon
本类。
super
是关键字官方解释
使用super
关键字发送消息会被编译器转化为调用objc_msgSendSuper
以及相关函数
dealloc分析
dealloc
流程图
通过流程图我们可以看到系统会自动进行一些操作
- 1、
C++
函数释放:objc_cxxDestruct
- 2、移除关联属性:
_object_remove_assocations
- 3、将弱引用自动设置nil:
weak_clear_no_lock(&table.weak_table, (id)this)
- 4、引用计数处理:
table.refcnts.erase(this)
- 5、销毁对象:
free(obj)
问题先行解答
1、initalize
和load
的区别是什么?
通过对initalize
、load
分析,可以在调用时机,调用顺序,执行方式三个方面比较。
调用时机
initialize
:方法是在类收到第一条消息之前被调用的,一个类只会调用一次,如果类没有初始化,这个也不会调用,在main函数之后调用
load
:方法是在程序加载类和分类的时候调用的,每个类和分类只会调用一次,调用和类有没有被使用无关,在main函数之前调用
调用顺序
initialize
:父类->本类,子类如果没有实现initialize
方法的话,也会自动调用父类的initialize
方法
load
:父类->本类->分类,分类后面加载的会覆盖前面加载的,子类中没有实现load
方法的话,不会调用父类的load
方法
执行方式
load
:根据load
方法的地址直接调用
initialize
:objc_msgSend
消息发送
2、如下代码输出结果是?
结果如下,具体原因见[self class]
、[super class]
分析
[self class]=ASSon,[super class]=ASSon
3、编译后的类能否添加成员变量?运行时创建的类能否添加成员变量?
(iOS-objc_object & objc_class)和iOS-类的加载(一)之前分析过实例变量是存储在class_ro_t
中,其是在编译阶段(类的加载)就生成的且是只读属性,后续无法修改。
通过runtime
相关方法可知是可以添加的,objc_allocateClassPair
创建类,class_addIvar
给类添加成员变量,objc_registerClassPair
注册类。但是有一点需要注意,在注册类之后,就不能再添加了。
4、如下代码输出结果是?
原类+[ASSon load]
分类2+[ASSon(grandson) load]
分类1+[ASSon(Son) load]
分类1+[ASSon(Son) initialize]
分类1-[ASSon(Son) faction1]
- 如果同名方法是普通方法(包括
initialize
),只调用分类方法。因为分类的方法是在类realize
实现之后再attach
进去的,插在类的方法的前面,所以只调用分类的方法。 - 如果同名方法是
load
方法,先原类load
,后分类load
可以参考iOS-类的加载(二)分析 注意如果有多个分类,加载顺序看这里分类的顺序
5、关联对象需要自己进行释放吗?
通过上面dealloc
分析,可知系统会自动进行移除关联属性,因此不需要自己进行释放。