一、了解
1. 概念初识:
以我们平时对代码的理解,我们都知道self代表的就是就是当前类,我们也经常用self来获取对象的实例变量或者调用实例方法。例如:self.name = @""等。而super则是父类,例如[super init]。
代码所示:
- (instancetype)init { self = [super init]; if (self) { self.sonName = @""; } return self; }
二. 代码实战:
/** JZPerson.h **/ @interface JZPerson : NSObject - (void)eat; @end /** JZPerson.m **/ #import "JZPerson.h" @implementation JZPerson - (void)eat { NSLog(@"%@", [super class]); NSLog(@"%@", [self class]); } @end /** main.m **/ int main(int argc, const char * argv[]) { @autoreleasepool { JZPerson* person = [[JZPerson alloc] init]; [person eat]; } return 0; }
让我们来猜猜以上代码结果是什么?没错,结果都是JZPerson,这是为什么呢,下面我们就来看看到底是什么原因:
我们用命令把代码转出cpp文件:clang -rewrite-objc JZPerson.m
1 NSLog((NSString *)&__NSConstantStringImpl__var_folders_d0_2_bdy_qx54l4v2pksls_339m0000gn _T_JZPerson_26882c_mi_0, ((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("JZPerson"))}, sel_registerName("class"))); 2 NSLog((NSString *)&__NSConstantStringImpl__var_folders_d0_2_bdy_qx54l4v2pksls_339m0000gn_T_JZPerson_26882c_mi_1, ((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class")));
区别就是两个函数:super调用的是class_getSuperclass,而self调用的则是objc_msgSend。
三、objc_msgSend与objc_msgSendSuper
函数的用法
id objc_msgSend(id self, SEL op, ...) //参数1:响应接收对象的实例;参数2:执行的方法..
objc_msgSendSuper(struct objc_super *super, SEL op, ...) //参数1:响应接收对象的实例;参数2:执行的方法..
代码实例:
/** JZPerson.h **/ @interface JZPerson : NSObject - (void)eat; @end /** JZPerson.m **/ @implementation JZPerson - (void)eat { NSLog(@"%@", [self class]); } @end /** JZSon.h JZSon继承自JZPerson **/ @interface JZSon : JZPerson - (void)eat; @end /** JZSon.m **/ #import "JZSon.h" #import <objc/message.h> @implementation JZSon - (void)eat { // [super eat]; typedef struct objc_super superStruct; superStruct superReceiver = { self, class_getSuperclass(object_getClass(self)) }; objc_msgSendSuper(&superReceiver, _cmd); // [self run]; objc_msgSend(self, @selector(run)); } - (void)run { NSLog(@"Run: %@", [self class]); } @end /** main.m **/ JZSon* son = [[JZSon alloc] init]; [son eat];
以上结果你可能没猜错,就是JZSon,哈哈哈。事实证明,虽然说我们调用了[super eat]的方法,但是实际上这个父类的响应接收实例仍然是当前调用的类实例。
四、最后再来一个实例加深大家的理解:
/** JZGrandSon.h JZGrandSon继承自上面的JZSon类 **/ #import "JZSon.h" @interface JZGrandSon : JZSon - (void)eat; @end /** JZGrandSon.m **/ #import "JZGrandSon.h" @implementation JZGrandSon @end /** main.m **/ int main(int argc, const char * argv[]) { @autoreleasepool { JZGrandSon* grandSon = [[JZGrandSon alloc] init]; [grandSon eat]; } return 0; }
此处代码执行到class_getSuperclass(object_getClass(self))将会奔溃,原因是此处调试时的结果我们可看到此处的父类是JZSon,而eat则是JZSon的实例方法,所以会执行死循环,导致奔溃。如下图所示:
五、总结
其实当我们调用了self的实例方法后,若当前类没有这个实例方法,那么将会从下至少开始查找类,直到找到合适的实例方法进行调用,而super则是从父类开始执行的这个查找方式。此处我们需要注意的是,若我们类中没有eat实例方法则会报错,毕竟没找到方法时肯定是会抛出异常。当理解了上面的objc_msgSendSuper实现方式,其它的就万变不离其宗了,哈哈哈,是不是很神奇呢?
借鉴文章:https://www.jianshu.com/p/87fe5efe104e
浙公网安备 33010602011771号