iOS—对象的本质(学习笔记)

news/2024/7/20 20:56:30 标签: ios, objective-c

只是小小记录一下,内容不完整

  1. OC底层实现是c\c++,oc的面向对象都是基于c\c++实现
  2. NSObject c++ 底层结构
struct NSObject_IMPL {
	//CLass 指针,64位占8个字节
	__unsafe_unretained Class isa;
};

//Class
typedef struct objc_class *Class

oc中的定义

@interface NSObject <NSObject> {

    Class isa  OBJC_ISA_AVAILABILITY;

}
//
typedef struct objc_class *Class;
  1. 一个NSObject对象占用多少内存?
  • 系统分配了16个字节给nsobject对象(通过malloc_size函数获得)
    通过查看alloc源码,可以看到为NSObject对象分配内存时,硬性规定至少为16字节
    在这里插入图片描述

  • 但NSObject对象实际只使用8个字节(64位环境下,通过class_getInstanceSize获得,其实际调用的函数如下,从注释中可知这是成员变量的大小,返回的是内存对齐后的大小)
    返回内存对齐
    在这里插入图片描述


#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <malloc/malloc.h>

@interface Student : NSObject

@property (nonatomic, assign) char num;
@property (nonatomic, assign) int age;

@end

@implementation Student

@end


int main(int argc, const char * argv[]) {
    @autoreleasepool {
//        // insert code here...
  
        Student *stu = [[Student alloc] init];
		stu.age = 10;
        stu.num = 'a';
        
        //class_getInstanceSize返回的是类的对象的成员变量所占内存大小(对齐过的)
        NSLog(@"%lu", class_getInstanceSize([Student class]));
		
		//返回stu指针所指向的内存大小
        NSLog(@"%lu", malloc_size((__bridge const void *)stu));
        
    }
    return 0;
}

//打印结果
//2021-07-21 16:19:36.975209+0800 对象的本质[27424:2825069] 16
//2021-07-21 16:19:36.977476+0800 对象的本质[27424:2825069] 16



//转为c++, Student本质
struct Student_IMPL {
	struct NSObject_IMPL NSObject_IVARS;   //只有isa, 8个字节
	char _num;  //1
	int _age;   //4
};

//NSOject本质
struct NSObject_IMPL {
	__unsafe_unretained Class isa;
};

在这里插入图片描述
分别存储着num,age(16进制, iOS是小端模式,内存读取要反着读)
在这里插入图片描述

!!!内存对齐 结构体嵌套 学习!!!!!

  1. 结构体内存对齐原则:
  • 第一个成员从偏移量为0开始存储,其余成员从地址为自身大小的整数倍开始存储。
  • 成员为结构体时,该结构体从地址为其最大成员的整数倍开始存储
  • 结构体的总大小,即sizeof()出来的结果是其最大成员大小的整数倍。
  1. 补充
  • 获取内存大小

  • sizeof:操作符:
    传入数据类型,输出内存大小。编译时固定,只与类型相关,与具体数值无关。(如:bool 2字节,int 4字节,对象(指针)8字节)

  • class_getInstanceSize: runtime的api,传入对象,输出对象实际所占的内存大小,本质是对象中成员变量的大小。与sizeof()返回值相同。

  • malloc_size:
    获取系统实际分配的内存大小
    有一个对齐的概念,与内存对齐概念不同,为oc对象分配的内存大小为16字节倍数,空间换时间,以16字节为一块,这就保证了CPU在读取的时候,按照块读取就可以,效率更高,同时还不容易混乱。()

  1. oc对象的分类
  • instance对象,实例对象
    在内存中存储的信息 有isa、成员变量的具体值
  • class对象,类对象
    类对象在内存只有一份

在这里插入图片描述
在这里插入图片描述
类对象存储的内容为
isa指针、superclass指针
类的属性信息、类的对象方法信息
类的协议信息、类的成员变量信息

  • meta-class对象,元类对象
    object_getClass获取元类对象,参数为类对象
    注意:class方法返回的对象一定是类对象,不是元类对象
    每个类只有一个元类对象
    在这里插入图片描述
    在这里插入图片描述
    元类对象存储的内容:
    isa、superclass指针
    类方法
  1. objc_getClass(<const char * _Nonnull name>)
    参数为字符串类名,返回相应的类对象

object_getClass(id _Nullable obj)
参数为实例对象,返回类对象
参数为类对象,返回元类对象
参数为元类对象,返回NSObject(基类)

  1. isa指针
    实例对象isa指向类对象
    类对象isa指向元类对象
    元类对象isa指向基类的元类对象
    在这里插入图片描述

实际上,在64bit开始,isa需要进行一次位运算即 isa & ISA_MASK,才能计算出指向的类或元类对象的真实地址
对于ISA_MASK的定义
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • struct objc_class的结构
//objc-runtime-new.h中

//继承的objc_object下面有复制部分 里面的成员只有isa
//
struct objc_class : objc_object {
  objc_class(const objc_class&) = delete;
  objc_class(objc_class&&) = delete;
  void operator=(const objc_class&) = delete;
  void operator=(objc_class&&) = delete;
   
    // Class ISA;
    Class superclass;
    cache_t cache;             // 方法缓存 formerly cache pointer and vtable
    class_data_bits_t bits;    // 用于获取具体的类信息 class_rw_t * plus custom rr/alloc flags

	...
}

struct objc_object {
private:
    isa_t isa;

public:
	...
	//一些方法
}

struct objc_class的结构可以简化为

struct objc_class {
   // Class ISA;
    Class superclass;
    cache_t cache;             // 方法缓存 formerly cache pointer and vtable
    class_data_bits_t bits;    // 用于获取具体的类信息 class_rw_t * plus custom rr/alloc flags

}

在这里插入图片描述

  • 对class_rw_t的理解
    rw代表可读可写
    类中的属性、方法、协议等信息都保存在class_rw_t中

  • 对class_ro_t的理解
    ro代表只读
    存储了当前类在编译期就确定了的属性、方法、协议

OC对象中存储的属性、方法、遵循的协议数据其实被存储在这两块儿内存区域的,而我们通过runtime动态修改类的方法时,是修改在class_rw_t区域中存储的方法列表


http://www.niftyadmin.cn/n/1617805.html

相关文章

iOS—[self class]和[super class]

先上一段代码 Person类继承NSObject Student类继承Person //Person类 继承自NSObject #import <Foundation/Foundation.h>interface Person : NSObjectend#import "Person.h"implementation Personend//Student类 继承自Person #import "Person.h"N…

iOS—属性关键字

文章目录property/synthesize/dynamic系统默认关键字原子性读写权限引用计数assignunsafe_unretainedweakstrongcopy一些问题property/synthesize/dynamic property 我们经常会看到 属性 getter setter 成员变量 但实际上property会生成setter、getter的方法声明synthesize会…

iOS—strong、weak的实现以及dealloc的调用流程

文章目录__strong修饰符ARC在编译器、运行期做了哪些工作&#xff1f;__weak修饰符__weak在使用过程中调用的函数objc_initWeakstoreWeakSideTableweak_table_t 结构weak_entry_t 结构weak_register_no_lock方法&#xff0c;添加弱引用weak_entry_for_referent &#xff0c;获取…

iOS—KVO用法及本质

文章目录KVOKVO 的使用KVO本质总结一些问题KVO KVO全称KeyValueObserving&#xff0c;键值监听&#xff0c;是苹果提供的一套事件通知机制。允许对象监听另一个对象特定属性的改变&#xff0c;并在改变时接受到事件。 KVO 的使用 三个方法 注册观察者 addObserver:(nonnull…

iOS—KVC本质

文章目录KVC一些API集合运算符setValue:forKey: 原理&#xff0c;赋值过程ValueForKey&#xff1a;原理&#xff0c;获值过程一些问题未完未完未完 后续补充KVC KVC全称是Key-Value-Coding&#xff0c;键值编码&#xff0c;可以通过一个key来访问某个属性 一些API 常见的API…

iOS—GCD详解

文章目录多线程编程进程线程线程与进程的关系多线程编程多线程编程的问题GCD什么是GCDGCD任务和队列GCD的使用步骤队列的创建队列的获取任务的创建方法任务与队列不同组合方式的区别同步执行 并发队列异步执行 并发队列同步执行 串行队列异步执行 串行队列同步执行 主队列…

iOS—pthread、NSThread简单了解

文章目录pthreadpthread的使用pthread其他相关方法NSThread创建、启动线程线程相关用法线程状态控制方法线程之间的通信NSThread线程安全pthread pthread是一套通用的多线程API&#xff0c;可以在Unix/Linux/Windows等系统跨平台使用&#xff0c;使用C语言编写&#xff0c;需要…

iOS—NSOperation、NSOperationQueue简单了解

文章目录NSOperation、NSOperationQueue为什么要使用NSOperation、NSOperationQueueNSOperation、NSOperationQueue操作和操作队列NSOperation、NSOperationQueue使用步骤NSOperation、NSOperation基本使用创建操作使用子类NSInvocationOperation使用子类NSBlockOperation使用继…