iOS 运行时

# iOS 运行时

两个重要的类型

idClass,在 objc/objc.h 中可以找到两者定义

typedef struct objc_object *id;
typedef struct objc_class *Class;

idClass 都是指向结构体指针,下面看看两个结构体objc_objectobjc_class 的区别:

struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;

根据Class的定义,Class 可以写成 struct objc_class ,那么结构体objc_objectobjc_class可以写成:

struct objc_object {
    struct objc_class *isa  OBJC_ISA_AVAILABILITY;
};

struct objc_class {
    struct objc_class *isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    struct objc_class *super_class                           OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;

两个重要概念 类对象 和 实例对象

在深入浅出Cocoa之类与对象中,objc_class 结构体的各成员介绍如下:

isa:是一个 objc_class 类型的指针,看到这里,想起我前面的引申解读了没?内存布局以一个 objc_class 指针为开始的所有东东都可以当做一个 object 来对待! 这就是说 objc_class 或者说类其实也可以当做一个 objc_object 对象来对待!对象是对象,类也是对象,是不是有点混淆?别急,ObjC发明(or 重用)了一个术语来区分这两种不同的对象:类对象(class object)与实例对象(instance object)。OK,名称混淆的问题解决,下面我将使用这两个术语来区分不同的对象,而使用“对象”这一术语来泛指所有的对象。ObjC还对类对象与实例对象中的 isa 所指向的类结构作了不同的命名:类对象中的 isa 指向类结构被称作 metaclass,metaclass 存储类的static类成员变量与static类成员方法(+开头的方法);实例对象中的 isa 指向类结构称作 class(普通的),class 结构存储类的普通成员变量与普通成员方法(-开头的方法)。
iOS 运行时_第1张图片

在objc 运行时中,有两个运行时方法

object_getClassobjc_getMetaClass

下面代码来自 [Cocoa]深入浅出Cocoa 之动态创建类

运行时添加myTest方法部分代码,是由我自己添加上去的,是为了验证一个疑问“class_addMethod”添加的方法是实例方法(- 号开头)还是类方法(+号开头)。

void ReportFunction(id self, SEL _cmd)
{
    NSLog(@" >> This object is %p.", self);
    NSLog(@" >> Class is %@, and super is %@.", [self class], [self superclass]);

    Class prevClass = NULL;
    int count = 1;
    for (Class currentClass = [self class]; currentClass; ++count)
    {
        prevClass = currentClass;

        NSLog(@" >> Following the isa pointer %d times gives %p", count, currentClass);

        currentClass = object_getClass(currentClass);
        if (prevClass == currentClass)
            break;
    }

    NSLog(@" >> NSObject's class is %p", [NSObject class]);
    NSLog(@" >> NSObject's meta class is %p", object_getClass([NSObject class]));
    NSLog(@" >> NSObject's meta class is %p", objc_getMetaClass(class_getName([NSObject class])));
    NSLog(@" >> self's meta class is %p", objc_getMetaClass(class_getName([self class])));
}

void test1(id self, SEL _cmd)
{
    NSLog(@"hello world!");
}


int main(int argc, char * argv[]) {
    @autoreleasepool {
        //为一个新类分配内存空间
        Class newClass = objc_allocateClassPair([NSString class], "NSStringSubclass", 0);
        //为类添加方法 ,(IMP)ReportFunction 方法的实现地址, “v@:” 是类型编码,v 表示void @表示对象 ,:表示方法选标(SEL ,即看做一个方法的id)
        //添加实例方法
        class_addMethod(newClass, @selector(report), (IMP)ReportFunction, "v@:");
        //添加类方法
        class_addMethod(object_getClass(newClass), @selector(myTest), (IMP)test1, "v@:");
        //注册类
        objc_registerClassPair(newClass);
        [newClass myTest];

        id instanceOfNewClass = [[newClass alloc] init];
        [instanceOfNewClass performSelector:@selector(report)];
        [instanceOfNewClass release];
    }
    return 0;
}

输出结果:

2016-04-22 16:41:26.436 Demo_ServiceFactory_0421[26738:1141044] hello world!
2016-04-22 16:41:26.452 Demo_ServiceFactory_0421[26738:1141044]  >> This object is 0x7fade1501e70.
2016-04-22 16:41:26.454 Demo_ServiceFactory_0421[26738:1141044]  >> Class is NSStringSubclass, and super is NSString.
2016-04-22 16:41:26.454 Demo_ServiceFactory_0421[26738:1141044]  >> Following the isa pointer 1 times gives 0x7fade14018d0
2016-04-22 16:41:26.454 Demo_ServiceFactory_0421[26738:1141044]  >> Following the isa pointer 2 times gives 0x7fade1401900
2016-04-22 16:41:26.454 Demo_ServiceFactory_0421[26738:1141044]  >> Following the isa pointer 3 times gives 0x109d12198
2016-04-22 16:41:26.455 Demo_ServiceFactory_0421[26738:1141044]  >> NSObject's class is 0x109d12170
2016-04-22 16:41:26.455 Demo_ServiceFactory_0421[26738:1141044]  >> NSObject's meta class is 0x109d12198
2016-04-22 16:41:26.455 Demo_ServiceFactory_0421[26738:1141044]  >> NSObject's meta class is 0x109d12198
2016-04-22 16:41:26.455 Demo_ServiceFactory_0421[26738:1141044]  >> self's meta class is 0x7fade1401900

原文解释:

根据前文中的类关系图,我们不难从执行结果中分析出 NSStringSubclass 的内部类结构:
1,对象的地址为 :0x7fade1501e70
2,class 的地址为:0x7fade14018d0
3,meta class 的地址为:0x7fade1401900
4,meta class 的 class 地址为:0x109d12198 (也是 NSObject 的 meta class)
5,NSObject 的 meta class 的 meta class 是其自身,地址为:0x109d12198

个人得出以下关系:

  1. NSLog(@" >> NSObject's class is %p", [NSObject class]);

     @interface NSObject <NSObject> {
        Class isa OBJC_ISA_AVAILABILITY; }

    根据NSObject定义,所以[NSObject class]返回的是 NSObject.isa

  2. NSLog(@" >> NSObject's meta class is %p", object_getClass([NSObject class]));

    object_getClass([NSObject class]) 返回的是 NSObject.isa.isa

  3. NSLog(@" >> NSObject's meta class is %p", objc_getMetaClass(class_getName([NSObject class])));

    objc_getMetaClass(class_getName([NSObject class])) 返回的是 NSObject.isa.isa

  4. 运行时添加类方法和实例方法的区别可以从代码中看出来,其实就是普通class 和 mate class 的区别**

    class_addMethod(**newClass**, @selector(report), (IMP)ReportFunction, "v@:");

    class_addMethod(**object_getClass(newClass)**, @selector(myTest), (IMP)test1, "v@:");

  5. 方法object_getClass的声明: Class object_getClass(id obj);

    参数obj 是一个id类型,在代码中可以看到我们会用object_getClass([NSObject class]),传入的参数是一个Calss类型!
    那么,也就是说这里会涉及到对象(结构体)的强制转换

    id object;
    Class class;
    id = class;

    可以使用一下代码进行验证:

    typedef struct people
    {
        NSString *name;
    
    } People;
    
    typedef struct xiaoming
    {
        NSString *name;
        int age;
    
    }Xiaoming ;
    
     People *pepple_point;
     Xiaoming xiaoming, *xiaoming_point;
     xiaoming.name = @"小明";
     xiaoming.age= 30;
     xiaoming_point = &xiaoming;
     pepple_point = xiaoming_point;
     NSLog(@"name:%@",pepple_point->name);
    

    输出结果:

    2016-04-22 17:33:07.104 Demo_ServiceFactory_0421[26939:1164162] name:小明

    当返回来赋值的时候,`xiaoming_point = pepple_point编译器是不会报错(指针之间都是4个字节,是允许强制转换的)。
    如果反过来赋值,如下:

            People *pepple_point,people;
            Xiaoming xiaoming, *xiaoming_point;
    
            people.name =  @"hello";
    
            pepple_point = &people;
            xiaoming_point = pepple_point;
            NSLog(@"name:%@",xiaoming_point->name);
            NSLog(@"name:%d",xiaoming_point->age);

    输出结果:

    2016-04-25 09:00:52.206 Demo_ServiceFactory_0421[38250:1932006] name:hello
    2016-04-25 09:00:54.718 Demo_ServiceFactory_0421[38250:1932006] name:1599636784

    可以发现xiaoming_point->age 输出一个奇怪的值!
    一句话来说:

    安全的强转是大类型(数据占用单元多)转为小类型(数据占用单元少)(所谓安全就是宁愿数据缺失也不能越界! )

    关于指针的强制转换可以参考文章 指针和指针强制转换( 回忆版 )——-让初学者理解

其他:

关于”v@:”这种字符串写法可以参考iOS学习之Objective-C 2.0 运行时系统编程-8类型编码
iOS 运行时_第2张图片

你可能感兴趣的:(ios,Class,指针,结构,运行时)