文章目录
1、super调用函数本质
class 方法的底层实现:
// 获取调用者对象的类
- (Class)class {
return object_getClass(self);
}
// 获取调用者对象的夫类
- (Class)superclass {
return class_getSuperclass(object_getClass(self));
}
super的底层实现【[super message]的底层实现】:
1、消息接收者仍然是子类对象。
2、从父类开始查找方法的实现。
示例:
#import "Person.h"
@interface Student : Person
@end
#import <Foundation/Foundation.h>
@interface Person : NSObject
- (void)run;
@end
- (instancetype)init
{
if (self = [super init]) {
NSLog(@"[self class] = %@", [self class]); // Student
NSLog(@"[self superclass] = %@", [self superclass]); // Person
NSLog(@"--------------------------------");
/**
* super调用实现本质:
* objc_msgSendSuper({self, [Person class]}, @selector(class));
*/
NSLog(@"[super class] = %@", [super class]); // Student
NSLog(@"[super superclass] = %@", [super superclass]); // Person
}
return self;
}
@end
2、isMemberOfClass、isKindOfClass区别
先看下底层逻辑:
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
+ (BOOL)isMemberOfClass:(Class)cls {
return object_getClass((id)self) == cls;
}
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
示例1:
id person = [[MJPerson alloc] init];
// 判断左边的实例对象是否等于右边的类
NSLog(@"%d", [person isMemberOfClass:[MJPerson class]]); // 1
NSLog(@"%d", [person isMemberOfClass:[NSObject class]]); // 0
// 判断左边的实例对象是否属于右边的类或子类
NSLog(@"%d", [person isKindOfClass:[MJPerson class]]); // 1
NSLog(@"%d", [person isKindOfClass:[NSObject class]]); // 1
示例2:
NSLog(@"%d", [NSObject isKindOfClass:object_getClass([NSObject class])]); // 1
NSLog(@"%d", [NSObject isMemberOfClass:object_getClass([NSObject class])]); // 1
NSLog(@"%d", [NSObject isKindOfClass:object_getClass([MJPerson class])]); // 0
NSLog(@"%d", [MJPerson isMemberOfClass:object_getClass([MJPerson class])]); // 1
// -------
// 这句代码的方法调用者不管是哪个类(只要是NSObject体系下的),都返回YES
NSLog(@"%d", [NSObject isKindOfClass:[NSObject class]]); // 1
NSLog(@"%d", [NSObject isMemberOfClass:[NSObject class]]); // 0
NSLog(@"%d", [MJPerson isKindOfClass:[MJPerson class]]); // 0
NSLog(@"%d", [MJPerson isMemberOfClass:[MJPerson class]]); // 0
总结:
1、实例方法是类的判断:
1、isMemberOfClass:判断左边的实例对象是否等于右边的类
2、isKindOfClass:判断左边的实例对象是否属于右边的类或子类
2、类方法是元类的判断:
1、正常情况下传参应该取元类对象进行判断断。
2、如果是传类对象判断,返回全部为0;除非右边入参为[NSObject class]
,此时方法调用者不管是哪个类(只要是NSObject体系下的),都返回YES。
3、以下代码能不能执行成功?如果可以,打印结果是什么?
考察知识点:
1、super 调用的本质
2、函数栈空间的分配问题
3、消息机制
4、访问成员变量的本质
1、指针分析
1、此时 cls 存放的是 MJPerson类的地址
2、obj 是MJPerson类的地址的指针
3、MJPerson.name 是 MJPerson 结构体中的成员变量,位于isa的下一个栈中。
4、因为MJPerson 没有初始化,所以实际情况是 name 属性没有被转成员变量,成为堆中的一个变量。
5、因此,此时 self.name 取的值是 MJPerson结构体isa的下一个栈信息。
2、[super viewDidLoad]
本质分析
底层结构:
struct abc = {
self,
[ViewController class]
};
objc_msgSendSuper2(abc, sel_registerName("viewDidLoad"));
从这个底层结构可知,MJPerson.isa 的下一个地址是self
、再下一个是 [ViewController class]
。那么其堆地址信息如下:
3、堆栈分析
4、打印取值
- (void)print
{
NSLog(@"my name is %@", self.name);
}
self.name
实际是取MJPerson结构体中isa
的下一个地址【self->_name
】,而MJPerson结构体中isa的下一个地址是ViewController中的self
的实例对象。
综上分析,最终print打印出来的值是 self
对象。
验证: