面试题class、super
本文Demo代码见gitHubDemo
面试题一
myAnimal.h
#import <Foundation/Foundation.h>
@interface myAnimal : NSObject
@end
myAnimal.m
#import "myAnimal.h"
@implementation myAnimal
@end
myPerson.h
#import "myAnimal.h"
@interface myPerson : myAnimal
@end
myPerson.m
#import "myPerson.h"
@implementation myPerson
-(instancetype)init{
if(self = [super init]){
NSLog(@"[self class] = %@",[self class]); //[self class] = myPerson
NSLog(@"[super class] = %@",[super class]);//[super class] = myPerson
NSLog(@"[self superclass] = %@",[self superclass]); //[self superclass] = myAnimal
NSLog(@"[super superclass] = %@",[super superclass]);//[super superclass] = myAnimal
}
return self;
}
@end
分析:xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp
[self class];输出:myPerson
===>
((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class"));
===>
objc_msgSend(self,@selector(class));
class方法
- (Class)class {
return object_getClass(self);
//这里self就是谁调用就是谁(也就是谁是消息接收者)
//传入实例对象,返回类对象名/传入类对象,返回的是元类对象名
}
Class object_getClass(id obj){
if (obj) return obj->getIsa(); //获取isa
else return Nil;
}
实例对象的isa指向元类
[super class];输出:myPerson
===>
((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("myPerson"))}, sel_registerName("class"));
===>
objc_msgSendSuper({self, class_getSuperclass([myPerson class])}, @selector(class))
===>
objc_msgSendSuper({self, [myAnimal class]}, @selector(class))
对于:[super class]消息接收者还是self(myPerson)本身自己,只是方法是从父类中查找的方法而已
此时里面的self还是myPerson,所以输出:myPerson
补充:
objc_msgSendSuper函数的底层
OBJC_EXPORT id _Nullable
objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
其中:objc_super为结构体:
#ifndef OBJC_SUPER
#define 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 */
};
#endif
[self superclass];输出:myAnimal
===>
((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("superclass"));
===>
objc_msgSend(self, @selector(superclass));
myPerson的父类是myAnimal
补充:
- (Class)superclass {
return [self class]->superclass;
}
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
......
}
[super superclass];输出:myAnimal
===>
((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("myPerson"))}, sel_registerName("superclass"));
===>
objc_msgSendSuper({self,[myAniaml class]}, @selector(superclass));
我们再来看看一个例子
myAnimal.h
#import <Foundation/Foundation.h>
@interface myAnimal : NSObject
-(void)run;
@end
myAnimal.m
#import "myAnimal.h"
@implementation myAnimal
-(void)run{
NSLog(@"%s",__FUNCTION__);
}
@end
myPerson.h
#import "myAnimal.h"
@interface myPerson : myAnimal
@end
myPerson.m
#import "myPerson.h"
#import <objc/runtime.h>
#import <objc/message.h>
@implementation myPerson
-(void)run{
//[super run];
struct objc_super arg = {self, [myAnimal class]};
((Class (*)(struct objc_super *, SEL))(void *)objc_msgSendSuper)(&arg, @selector(run));
}
@end
myPerson *p = [[myPerson alloc]init];
[p run];
打印:
-[myAnimal run]
总结:super
[super message]的底层实现
1.消息接收者仍然是子类对象
2.从父类开始查找方法的实现
面试题二
BOOL res1 = [[NSObject class] isKindOfClass:[NSObject class]];//1
BOOL res2 = [[NSObject class] isMemberOfClass:[NSObject class]];//0
BOOL res3 = [[myPerson class] isKindOfClass:[myPerson class]];//0
BOOL res4 = [[myPerson class] isMemberOfClass:[myPerson class]];//0
BOOL res5 = [[myPerson class] isMemberOfClass:[NSObject class]];//0
补充:
底层:
NSObject.mm文件
class方法
- (Class)class {
return object_getClass(self);
}
Class object_getClass(id obj){
if (obj) return obj->getIsa();
else return Nil;
}
============================================
+ (BOOL)isMemberOfClass:(Class)cls {
return object_getClass((id)self) == cls;
}
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
isKindOfClass来确定一个对象是否是一个类的成员,或者是派生自该类的成员(对象包括:类对象和元类对象)
isMemberOfClass只能确定一个对象是否是当前类的成员
我们在来看看
NSLog(@"%d", [[NSObject class] isKindOfClass:[NSObject class]]); //1
NSLog(@"%d", [[NSObject class] isMemberOfClass:[NSObject class]]); //0
NSLog(@"%d", [[myPerson class] isKindOfClass:[myPerson class]]);//0
NSLog(@"%d", [[myPerson class] isMemberOfClass:[myPerson class]]);//0
等价==>(isa指针)左边的isa指向是否是右边的家伙(实例对象isa指向类对象,类对象的isa指向元类isa,元类对象的isa指向NSObject元类对象)
// 这句代码的方法调用者不管是哪个类(只要是NSObject体系下的),都返回YES
NSLog(@"%d", [NSObject isKindOfClass:[NSObject class]]); // 1 //NSObject的元类的superclass是指向类对象的
NSLog(@"%d", [NSObject isMemberOfClass:[NSObject class]]); // 0 左边是元类对象(类对象的类对象),而右边是类对象
NSLog(@"%d", [myPerson isKindOfClass:[myPerson class]]); // 0
NSLog(@"%d", [myPerson isMemberOfClass:[myPerson class]]); // 0
NSLog(@"--------");//类对象
id person = [[myPerson alloc] init];
NSLog(@"%d", [person isMemberOfClass:[myPerson class]]);//1
NSLog(@"%d", [person isMemberOfClass:[NSObject class]]);//0
NSLog(@"%d", [person isKindOfClass:[myPerson class]]);//1
NSLog(@"%d", [person isKindOfClass:[NSObject class]]);//1
NSLog(@"--------"); //元类对象
NSLog(@"%d", [myPerson isMemberOfClass:object_getClass([myPerson class])]);//1
NSLog(@"%d", [myPerson isKindOfClass:object_getClass([NSObject class])]);//1
NSLog(@"%d", [myPerson isKindOfClass:[NSObject class]]); //1
左边是实例对象,右边得是类对象
左边是类对象,右边得是元类对象
面试题三
myPerson.h
#import <Foundation/Foundation.h>
@interface myPerson : NSObject
@property(strong,nonatomic)NSString *name;
-(void)print;
@end
myPerson.m
#import "myPerson.h"
@implementation myPerson
-(void)print{
NSLog(@"name = %@",self.name);
}
@end
#import "ViewController.h"
#import "myPerson.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
id cls = [myPerson class];
void *obj = &cls;// 将 obj 作为一个指向 myPerson Class 的指针
[(__bridge id)obj print]; //通过(__bridge id) 将指针转换 成 Objective-C 的对象
}
@end
打印:
name = <ViewController: 0x7fcfb0d055c0>
1.print为什么能够调用成功?
2.为什么self.name变成了ViewController等其他内容
runtime_14.png
友情链接:
网友评论