美文网首页
Objective-C对象的分类

Objective-C对象的分类

作者: 紫荆秋雪_文 | 来源:发表于2018-06-30 00:19 被阅读41次

    一、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对象在内存中存储的信息包含

    • isa指针
    • 成员变量 instance对象在内存职工存储信息.png

    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)
      • 类的成员变量信息 class对象内存存储信息.png

    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指针
      • superclass
      • 类方法信息 meta-class内存存储信息.png

    三、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对象,最后找到对象方法的实现进行调用 instance对象中的isa.png
    • 测试源码
    /***********  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,最后找到类方法的实现并进行调用 class对象中的isa.png
    • 测试源码
    /************ 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对象 isa指针.png

    四、superclass指针

    通过创建RevanStudent类、RevanPerson类、NSObject类来分析superclass,并且RevanStudent类继承于RevanPerson类,RevanPerson类继承于NSObject superclass.png

    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对象方法。如果还是没有找到就继续在父类的父类中寻找 superclass用来指向父类.png

    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&&superclass.png

    isa&&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对象

    相关文章

      网友评论

          本文标题:Objective-C对象的分类

          本文链接:https://www.haomeiwen.com/subject/smroyftx.html