一、Objective-C对象的分类
Objective-C中的对象,简称OC对象,主要可以分为3种
- instance对象(实例对象)
- class对象(类对象)
- meta-class对象(元类对象)
二、instance对象
1、instance对象就是通过类alloc出来的对象,每次调用alloc都会产生新的instance对象
// RevanPerson
#import <Foundation/Foundation.h>
@interface RevanPerson : NSObject {
@public
int _age;
}
@end
// ViewController
#import "ViewController.h"
#import "RevanPerson.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSObject *obj = [[NSObject alloc] init];
RevanPerson *person = [[RevanPerson alloc] init];
person->_age = 18;
NSLog(@"%@\n%@", obj, person);
}
@end
- obj是NSObject的instance对象,person是RevanPerson的instance对象;他们是不同的实例对象,分别占用两块不同内存
2、instance对象在内存中存储的信息包含
3、class对象(类对象)在内存中存储的信息
#import "ViewController.h"
#import "RevanPerson.h"
#import <objc/runtime.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSObject *obj1 = [[NSObject alloc] init];
NSObject *obj2 = [[NSObject alloc] init];
Class obj_class1 = [obj1 class];
Class obj_class2 = [obj2 class];
Class obj_class3 = [NSObject class];
//使用 runtime 获取[实例对象]的[类对象]
Class obj_class4 = object_getClass(obj1);
Class obj_class5 = object_getClass(obj2);
NSLog(@"\n%p\n%p\n%p\n%p\n%p\n", obj_class1, obj_class2, obj_class3, obj_class4, obj_class5);
}
@end
打印输出:
0x106cdeea8
0x106cdeea8
0x106cdeea8
0x106cdeea8
0x106cdeea8
- obj_class1、obj_class2、obj_class3、obj_class4、obj_class5都是NSObject的class对象(类对象),从打印输出可以他们都是相同的,
- 每一个类在内存中有且只有一个class对象(类对象)
- class对象在内存中存储的信息包括:
- isa指针
- superclass指针
- 类的属性信息(@property)
- 类的对象方法信息(instance method)
- 类的协议信息(protocol)
-
类的成员变量信息
4、meta-class
#import "ViewController.h"
#import "RevanPerson.h"
#import <objc/runtime.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSObject *revan_obj = [[NSObject alloc] init];
RevanPerson *revan_person = [[RevanPerson alloc] init];
Class NSObjectClass = [NSObject class];//类对象
Class NSObjectClass1 = object_getClass(revan_obj);//类对象(runtime)
Class NSObjectMetaClass = object_getClass(NSObjectClass);//元类对象(runtime)
NSLog(@"\nNSObjectClass:%p\nNSObjectClass1:%p\nNSObjectMetaClass:%p\n", NSObjectClass, NSObjectClass1, NSObjectMetaClass);
Class RevanPersonClass = [RevanPerson class];//类对象
Class RevanPersonClass1 = object_getClass(revan_person);//类对象(runtime)
Class RevanPersonMetaClass = object_getClass(RevanPersonClass);//元类对象(runtime)
NSLog(@"\nRevanPersonClass:%p\nRevanPersonClass1:%p\nRevanPersonMetaClass:%p\n", RevanPersonClass, RevanPersonClass1, RevanPersonMetaClass);
}
@end
输出打印:
NSObjectClass:0x11099cea8
NSObjectClass1:0x11099cea8
NSObjectMetaClass:0x11099ce58
RevanPersonClass:0x10f9f2ee0
RevanPersonClass1:0x10f9f2ee0
RevanPersonMetaClass:0x10f9f2eb8
- 使用runtime方法object_getClass(<#id _Nullable obj#>)来获取meta-class
- 当obj传入的是instance对象时,获得的是class对象
- 当obj传入的是class对象时,获得的是meta-class对象
- 每个类在内存中有且只有一个meta-class对象
- meta-class对象和class对象的内存结构是一样的(都是Class类型结构),但是用途不同
- meta-class对象在内存中存储的主要信息包括
三、isa指针
在instance对象、class对象、meta-class对象的内存存储中都有一个isa指针,那么isa指针有什么用?
1、isa指针在instance对象中的作用
类的instance对象&class对象&meta-class对象.png
- 情景:instance对象调用对象方法,这个过程是怎么实现的?
- oc语言是一门动态语言也是一门消息语言,当一个instance对象调用一个方法的时候,底层的实现是给这个instance对象发送一个消息,从上图我们知道instance对象在内存中只存储了isa指针和成员变量,是没有存储方法的;对象方法信息是存储在class对象的内存中的,那么如何才能找到class对象?这时候就需要用到isa指针。系统会通过isa指针找到instance对象对应的class对象,从class对象的对象方法列表中查找是否有方法和刚才发出的方法匹配,如果匹配就执行方法,如果没有找到就会报错:unrecognized selector
- instance的isa指向class
-
当调用对象方法时,通过 instance对象的isa找到class对象,最后找到对象方法的实现进行调用
- 测试源码
/*********** RevanPerson *************/
#import <Foundation/Foundation.h>
@interface RevanPerson : NSObject
- (void)instanceRevanPersonFun;
@end
#import "RevanPerson.h"
@implementation RevanPerson
@end
/*********** 测试 instance对象调用对象方法 *************/
#import "ViewController.h"
#import "RevanPerson.h"
#import <objc/runtime.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//instance对象
RevanPerson *revan_p = [[RevanPerson alloc] init];
//instance对象对用方法
[revan_p instanceRevanPersonFun];
}
@end
2、isa指针在class对象中的作用
- 情景:class对象调用类方法
- 通过上面的图可以知道class对象的内存中并没有类方法的信息,类方法信息是存储在meta-class对象的内存中,这就需要使用class对象中的isa指针来寻找到meta-class对象,最后找到类方法的实现并进行调用,如果没有找到就会报错:unrecognized selector
- class的isa指针指向meta-class
-
当调用类方法,通过class的isa找到meta-class,最后找到类方法的实现并进行调用
- 测试源码
/************ RevanPerson *************/
#import <Foundation/Foundation.h>
@interface RevanPerson : NSObject
/**
对象方法
*/
- (void)instanceRevanPersonFun;
/**
类方法
*/
+ (void)classRevanPersonFun;
@end
#import "RevanPerson.h"
@implementation RevanPerson
@end
/************ 测试代码 ************/
#import "ViewController.h"
#import "RevanPerson.h"
#import <objc/runtime.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//调用类方法
[RevanPerson classRevanPersonFun];
}
@end
- 小结:isa指针在instance对象、class对象、meta-class对象中的作用:
- instance对象的isa指向class对象
-
class对象的isa指向meta-class对象
四、superclass指针
通过创建RevanStudent类、RevanPerson类、NSObject类来分析superclass,并且RevanStudent类继承于RevanPerson类,RevanPerson类继承于NSObject
1、RevanStudent类的instance对象调用自己类中的对象方法在上面已经分析过了,由于RevanStudent类继承于RevanPerson类,那么RevanStudent类的instance对象可以调用RevanPerson类中的对象方法,同理也可以调用NSObject类中的对象方法,这个过程是如何完成的
/************ RevanPerson *************/
#import <Foundation/Foundation.h>
@interface RevanPerson : NSObject
/**
对象方法
*/
- (void)instance_RevanPersonFun;
@end
#import "RevanPerson.h"
@implementation RevanPerson
/**
对象方法
*/
- (void)instance_RevanPersonFun {
NSLog(@"instance_RevanPersonFun");
}
@end
/************ RevanPerson *************/
#import "RevanPerson.h"
@interface RevanStudent : RevanPerson
/**
对象方法
*/
- (void)instance_RevanStudentFun;
@end
#import "RevanStudent.h"
@implementation RevanStudent
/**
对象方法
*/
- (void)instance_RevanStudentFun {
NSLog(@"instance_RevanStudentFun");
}
@end
/************ 测试代码 ************/
#import "ViewController.h"
#import "RevanPerson.h"
#import "RevanStudent.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//创建revan_s
RevanStudent *revan_s = [[RevanStudent alloc] init];
//调用父类对象方法
[revan_s instance_RevanPersonFun];
}
@end
输出打印:
instance_RevanPersonFun(RevanPerson类中的对象方法的输出)
- 相对应instance对象(revan_s)来说,instance_RevanPersonFun对象方法是存储在RevanPerson类的class对象的内存中,而不是存储在RevanStudent类的class对象的内存中,所以肯定不是通过isa指针找到的instance_RevanPersonFun对象方法。superclass是用来指向父类。那么这个调用过程如下
-
revan_s实例对象通过isa指针找到class对象,并且查找对象方法信息,发现并没有instance_RevanPersonFun这个对象方法。再通过class对象中的superclass指针找到父类的class对象并从对象方法中查找,终于找到了instance_RevanPersonFun对象方法。如果还是没有找到就继续在父类的父类中寻找
2、meta-class对象中的superclass
- 情景:RevanStudent调用RevanPerson的类方法
/************ RevanStudent *************/
#import "RevanPerson.h"
@interface RevanStudent : RevanPerson
/**
对象方法
*/
- (void)instance_RevanStudentFun;
/**
类方法
*/
+ (void)class_RevanStudentFun;
@end
#import "RevanStudent.h"
@implementation RevanStudent
/**
对象方法
*/
- (void)instance_RevanStudentFun {
NSLog(@"instance_RevanStudentFun");
}
/**
类方法
*/
+ (void)class_RevanStudentFun {
NSLog(@"class_RevanStudentFun");
}
@end
/************ RevanPerson *************/
#import <Foundation/Foundation.h>
@interface RevanPerson : NSObject
/**
对象方法
*/
- (void)instance_RevanPersonFun;
/**
类方法
*/
+ (void)class_RevanPersonFun;
@end
#import "RevanPerson.h"
@implementation RevanPerson
/**
对象方法
*/
- (void)instance_RevanPersonFun {
NSLog(@"instance_RevanPersonFun");
}
/**
类方法
*/
+ (void)class_RevanPersonFun {
NSLog(@"class_RevanPersonFun");
}
@end
/************ 测试代码 ************/
#import "ViewController.h"
#import "RevanPerson.h"
#import "RevanStudent.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//调用父类的类方法
[RevanStudent class_RevanPersonFun];
}
@end
打印输出:
class_RevanPersonFun(RevanPerson的类方法)
-
RevanStudent在调用类方法时,首先会通过RevanStudent类的class对象中的isa指针到RevanStudent类的meta-class对象的类方法中查找是否有这个被调用的类方法,如果没有就会通过RevanStudent类的meta-class对象中的superclass指针指向父类的meta-class对象在类方法中继续查找,如果找到就调用执行。如果没有找到就继续想父类的meta-class对象中的类方法中寻找
meta-class对象中的superclass.png
五、总结
- isa指针总结
- instance对象的isa指针指向class对象
- class对象的isa指针指向meta-class对象
- meta-class的isa指针指向基类的meta-class对象
- superclass指针总结
- class对象的superclass指针指向父类的class对象,如果没有父类,superclass指针为nil
- meta-class的superclass指针指向父类的meta-class对象
- 基类的meta-class的superclass指针指向基类的class对象
- instance调用对象方法
- isa找到class对象,方法不存在,就通过superclass找到父类的class对象
- class对象调用类方法
- isa找到meta-class对象,方法不存在,就通过superclass找到父类的meta-class对象