一、概述
类的本质:
类的本质其实是一个对象(类对象)
Person *p1 = [Person new];
p1是一个实例对象,而Person就是一个Class类型的类对象。
关于类对象:
1.类对象在程序运行时一直存在。
2.类对象是一种数据结构,存储类的基础信息:类的大小,类的名称,类的版本以及消息与函数的映射表等。
3.类对象所保存的信息在程序编译时确定,在第一次使用该类的时候被加载到内存中。
4.类对象代表类,类方法属于类对象。
5.如果消息接受者是类名,则类名代表类对象。
6.运行时,所有类的实例都由类对象生成,类对象会把实例的isa的值修改为自己的地址,每个实例的isa指针都指向该实例的类对象。
7.从类对象可以知道父类信息,可以相应的方法等。
8.类对象只能使用类方法,不可以使用对象方法。
二、类对象的获取和使用
1.类对象的获取
可以通过实例对象获取,也可以通过类名获取:
Animal *a = [Animal new];
Class c1 = [a class]; //通过对象名获取
Class c2 = [Animal class]; //通过类名获取
2.类对象的使用
可以用来创建实例对象,也可以用来调用类方法
Animal *a2 = [c1 new];//通过类对象创建实例对象
[c1 eat];//通过类对象调用类方法
示例代码:
Animal.h
#import <Foundation/Foundation.h>
@interface Animal : NSObject
-(void) test;
+(void) test;
@end
Animal.m
#import "Animal.h"
@implementation Animal
-(void) test{
NSLog(@"\n-执行的是对象方法");
}
+(void) test{
NSLog(@"\n+执行的是类方法");
}
@end
main.m
#import <Foundation/Foundation.h>
#import "Animal.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Animal *a = [Animal new];
//类对象的获取
Class c1 = [a class]; //1.通过实例对象名获取类对象
Class c2 = [Animal class]; //2.通过类名获取类对象
NSLog(@"c1的地址:%p",c1); //输出:c1的地址:0x1000011e0
NSLog(@"c2的地址:%p",c2); //输出:c2的地址:0x1000011e0
//类方法的使用
Animal *a2 = [c1 new]; //1.通过类对象创建实例对象
[a2 test]; //输出:-执行的是对象方法
[c1 test]; //输出:+执行的是类方法 2.通过类对象调用类方法
}
return 0;
}
三、SEL类型
SEL:全称selector,表示方法的存储位置。
寻找test方法的过程:
1.把test方法名包装成sel类型的数据。
2.根据SEL数据找到对应的方法地址。
3.根据方法地址调用相应方法。
注意:
1.寻找方法的过程中有缓存,第一次寻找的时候是一个一个对比寻找的,非常消耗性能,之后再用到该方法的时候就直接调用了。
2.SEL其实是对方法的一种包装,将方法包装成一个SEL类型的数据,去寻找对应的方法地址,找到方法地址之后就可以调用方法。这些都是运行时特性,发送消息就是发送SEL,然后根据SEL找到地址,调用方法。
实例代码:
#import <Foundation/Foundation.h>
#import "Animal.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Animal *a = [Animal new];
//类对象的获取
Class c1 = [a class]; //通过实例对象名获取类对象
SEL s1 = @selector(test);
[a performSelector:s1]; //输出:-执行的是对象方法
[c1 performSelector:s1]; //输出:+执行的是类方法
}
return 0;
}