一、概述
类的本质:
类的本质其实是一个对象(类对象)
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;
}