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 对象。
验证: