iOS原理(一)----OC对象结构

iOS原理(一)----OC对象结构

创建一个普通的NSObject对象如下:

NSObject *obj = [[NSObject alloc] init];

NSObject的声明如下:

@interface NSObject  {
    Class isa;
}

查看其变异生成的C++代码为:

struct NSObject_IMPL {
    Class isa;
};

Class为一个结构体的指针:

typedef struct objc_class *Class;

在64位系统上,指针的大小为8个字节.所以class_getInstanceSize([NSObject class])获取的大小为8.

Snip20181108_1.png

但实际obj对象为多少?用malloc_size((__bridge const void *)(obj))函数得到大小为16.

Snip20181108_3.png

查看runtime源码得知class_getInstanceSize()实现如下:

size_t class_getInstanceSize(Class cls)
{
    if (!cls) return 0;
    // 返回对齐过的实例大小
    return cls->alignedInstanceSize();
}

// 返回成员变量的大小
uint32_t alignedInstanceSize() {
        return word_align(unalignedInstanceSize());
    }

由上面可以发现class_getInstanceSize()是返回成员变量的大小,obj对象只有一个Class类型的指针,在64位系统上是8个字节,所以上面打印输出为8.

查看alloc调用了一个函数如下:

    size_t instanceSize(size_t extraBytes) {
        size_t size = alignedInstanceSize() + extraBytes;
        // CF requires all objects be at least 16 bytes.
        if (size < 16) size = 16;
        return size;
    }

指出所有对象创建出来至少为16字节,虽然函数中这里size为8,所以说malloc_size()函数得到的值是16字节.可以看出``class_getInstanceSize()函数是对象理论上需要的内存,alloc出来的大小是对象实际对象需要的内存.从xcode调试可以看出obj`分配了16字节内存,实际只用了8个字节.

Snip20181109_4.png

再新建一个Animal类,一个int类型的age成员变量.

@interface Animal : NSObject {
    @public
    int _age;
}

@end

@implementation Animal

@end

其生成的c++代码为:

struct Animal_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    int _age;
};

据此我们可以推测出class_getInstanceSize()函数得到的大小为12字节,malloc_size()函数为16字节,但实际回事多少呢?打印如下:

Snip20181109_5.png

发现都是16字节,这是因为结构体大小有个内存对齐规则,用class_getInstanceSize()得到的大小就为16字节.

Snip20181109_7.png

Animal增加两个成员变量,heigtweight都是int类型,查看其编译生成C++源码为:

struct Animal_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    int _age;
    int _height;
    int _weight;
};

根据推测结构体大小,推测class_getInstanceSize()函数得到Animal对象应该为24字节,malloc_size()也应该为24字节.实际打印如下:

Snip20181109_8.png

实际用malloc_size()函数得到为32字节,查看源码有这样一句:

Snip20181109_9.png

有Buckets sized东西,系统分配内存的时候,只会分配16字节的倍数的内存,所以上面的的到大小为32字节.

Snip20181109_10.png

OC中的对象分为三种对象:

  • 实例对象,就是前面创建的对象,里面存放isa指针(指向类对象)和成员变量的值信息.
  • 类对象,Class,存放isa指针(需要 & ISA_MASK,指向元类对象),superclass指针(指向父类),协议信息,属性信息,成员变量描述信息,对象方法信息...
  • 元类对象,isa指针(需要 & ISA_MASK,指向根原类对象),superclass指针(指向父元类对象),类方法信息...

类对象结构如下:

Snip20181109_13.png
Snip20181109_14.png
Snip20181109_15.png

如果一个类方法层层网上找,如果直到根源类都没有此方法时,就是就根类去找对象方法,如果还找不到,就会抛出错误.我们NSObject添加一个对象方法,给Animal类声明一个类方法,并没有实现它,然后调用Animal的eat类方法,调用成功

Snip20181109_11.png
@interface NSObject (Eat)

- (void)eat;

@end

@implementation NSObject (Eat)

- (void)eat {
    NSLog(@"NSObeat - eat");
}

@end


@interface Animal : NSObject {
    @public
}

+ (void)eat;

@end

@implementation Animal

@end
Snip20181109_12.png

你可能感兴趣的:(iOS原理(一)----OC对象结构)