Objective-C本质探究

Objective-C属于一种基于c/c++而封装的面向对象的高级语言,其编译过程如下:
在这里插入图片描述
即:Objective-C的面向对象都是基于C/C++的数据结构实现的,而Objective-C的对象、类主要是基于C/C++的结构体实现的,本质上Objective-C的对象、类就是结构体

为什么OC对象的本质是结构体

NSObject

首先我们先创建一个程序
在main.m文件中创建一个NSObject的对象

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSObject *obj = [[NSObject alloc] init];
    }
    return 0;
}

使用终端将main.m编译成.cpp文件,命令如下:
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp
*打开main.cpp文件,搜索NSObject,可找到如下代码:

istruct NSObject_IMPL {
    Class isa;
};

即:创建的obj就是一个结构体,这个结构体就是NSObject对象在内存中的本质。
另外,我们按住command点击进NSObject里面看一下,也可以看到这样一个结构:

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

然后我们按住command键点击Class进入窥探一下这个Class,我们看到这样一个结构:

typedef struct objc_class *Class;

这说明Class是一个结构体指针。所以isa也就是一个指针。因此NSObject_IMPL这个结构体中就是包含了一个结构体指针isa,它所占的内存大小就是这个isa指针所占的内存大小。

在64位环境中,指针占8个字节,在32位环境中,指针占4个字节。
NSObject_IMPL这个结构体只有一个成员isa指针,所以结构体的地址就是存放isa指针的地址。比如isa这个指针的地址是0x100400100,那么就有objc=0x100400110。

自定义的类

在main.m文件中创建一个继承自NSObject的Person对象

@interface Student: NSObject {
    @public
    int _age;
    int _score;
}
@end

@implementation Student
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Student *stu = [[Student alloc] init];
        stu->_age = 4;
        stu->_score=80;
    }
    return 0;
}

同上的方式生成main.cpp文件,搜索Student,可看到如下内容:

struct Student_IMPL {
    struct NSObject_IMPL NSObject_IVARS; /// 相当于 Class isa;
    int _age;
    int _score;
};

/// 由上得到,即一个初创的Student对象所占的内存大小为:isa的大小 + int的大小*2

struct Student_IMPL {
    Class isa;
    int _age;
    int _score;
};

假设Student对象是一个结构体的话
/// 定义这样的结构体

struct Student_IMPL {
    Class isa;
    int _age;
    int _score;
};
@interface Student: NSObject {
    @public
    int _age;
    int _score;
}
@end

@implementation Student
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Student *stu = [[Student alloc] init];
        stu->_age = 4;
        stu->_score=80;
       
        struct Student_IMPL *stu2 = (__bridge struct Student_IMPL *)stu;
        /// 如果打印结果是 4 - 80 的话,即可证明student对象本质上就是一个结构体
        NSLog(@"%d - %d", stu2->_age, stu2->_score);
    }
    return 0;
}

由打印结果反推得出:student对象本质上就是一个结构体

扩展:NSObject所占内存大小是多少?

因为OC对象的本质是结构体,那NSObject所占的内存大小就是结构体指针所占的大小。
其实不然,准确的说法是:(以64bit为例)
1、从内存中动态分配的大小是由malloc_size()函数获取的,即16
2、NSObject对象真正使用的大小是 8
所以一个NSObject对象在64位环境中占8字节,在32位环境中占4字节。我们接着往下看,通过读取内存来验证我们的想法。

  • class_getInstanceSize()方法 (可以通过运行时中的class_getInstanceSize:方法直接获取NSObject的内存大小)
  • class_getInstanceSize()返回的NSObject_IMPL的大小。
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSObject *obj = [[NSObject alloc] init];
        // 16个字节
        
        // 获得NSObject实例对象的成员变量所占用的大小 >> 8
        NSLog(@"%zd", class_getInstanceSize([NSObject class]));
        
        // 获得obj指针所指向内存的大小 >> 16
        NSLog(@"%zd", malloc_size((__bridge const void *)obj));
        
        // 什么平台的代码
        // 不同平台支持的代码肯定是不一样
        // Windows、mac、iOS
        // 模拟器(i386)、32bit(armv7)、64bit(arm64)
    }
    return 0;
}

运行上面的代码我们可以看到NSObject所占的内存大小
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值