聊一聊对象(一)

2020-12-16  本文已影响0人  晨阳Xia

Apple源码

iOS开发之OC对象本质

一、相关内容

1.1LLDB 知多少

1.2 读取函数寄存器

register read x0 : 函数的第一个参数
register read x1 : 函数的第二个参数
memory read : 读取内存

二、alloc的流程

案例代码:

@interface Person : NSObject

@property(assign, nonatomic) int age;

@end

Person *p = [Person alloc]; // objc_msgSend(Person, SEL(alloc));

2.1 alloc做了什么:(源码分析)

alloc已经生成了对象,并返回对象 obj

p.age = 10;
NSLog(@"p.age--%ld",(long)p.age);
p.age--:10 // 没有发送init消息,依然可以创建p对象,并进行赋值操作。

// alloc内部实现
+(id)alloc {
    return _objc_rootAlloc(self);
}

_objc_rootAlloc(Class cls) {
    return callAlloc(cls, false/*checkNil*/,true/*allocWithZone*/)
}

callAlloc(Class cls, bool checkNil, bool allocWithZone = false) {  
    ...
    id obj = class_createInstance(cls, 0);
    ...
    return obj;
}

到此为止,alloc完成了创建对象对的过程。

2.2 init的流程(源码分析)

p1 = [p init]; // objc_msgSend(p, SEL(init));
NSLog(@"p1.age--%ld",(long)p1.age);
p1.age--:10 

- (id)init {
    return _objc_rootInit(self);
}
_objc_rootInit(id obj) {
    // In practice ,it will be hard to rely on this function
    // Many class do not properly chain -init calls
    return obj;
}

2.3 init做了什么:

直接return obj。init相当于一个工厂类,是为了让重写它,实现自己的方法。既然alloc已经生成了对象,是不是我们也可以不写init?不可以。因为Foundation框架在init里做了必要工作。如果没有init,那么你创建就是一个没有任何功能的对象。

三、什么是字节对齐?为什么要字节对齐?

3.1 字节对齐:

iOS在arm中按照8字节对齐,开辟的内存一定是8的倍数。比如我需要9个字节,那我开辟的自己是 16个字节。字节对齐一定是浪费空间的。

3.2 为什么要字节对齐:

因为硬件决定的。有些cpu只能从偶数开始读数据。提高读取效率。
代码对齐的源码:

WORD_MASK = 7;
int word_align(int x) {
    // (x + 7) / 8 * 8 
    // (x + 7) >> 3 << 3
    return (x + WORD_MASK) & ~WORD_MASK; 
}

字节对齐案例:

@interface Person : NSObject

@property(assign, nonatomic) int age;
@property(assign, nonatomic) double height;

@end

Person *p = [Person alloc];
p.age = 1;
p.height = 1.85;

p共有 24个字节
age : 4个字节
height : 8 个字节
isa : 8个字节
4 + 8 + 8 = 20
因为iOS在arm中按照8字节对齐,所以p供分配了 24个字节

p中存在三个指针:
0x100f4fd90: isa: 8字节 age: 4字节
0x100f4fda0: height: 8字节
16进制代码如下:
0x100f4fd90: c1 11 00 00 01 80 1d 00 00 00 00 01 00 00 00 00
0x100f4fda0: 9a 99 99 99 99 99 fo 3f
打印double地址:
p *(double *)0x100f4fda0
// (double) $1 = 1.8500000000000001

3.3 结构体的大小必须是最大成员大小的倍数

@interface CustomPerson : NSObject{
    int _age;
}
@end

@implementation CustomPerson
@end

@interface Student : CustomPerson{
    int _no;
}
@end

@implementation Student

@end
Student *student = [[Student alloc] init];
NSLog(@"%zu", class_getInstanceSize([Student class]));
NSLog(@"%zu", malloc_size((__bridge const void *)student));
2020-12-16 15:32:53.592040+0800  16
2020-12-16 15:32:53.592230+0800  16

将student中的_no换成double类型

@interface CustomPerson : NSObject{
    int _age;
}
@end

@implementation CustomPerson
@end

@interface Student : CustomPerson{
    double _no;
}
@end

@implementation Student

@end

Student *student = [[Student alloc] init];
NSLog(@"%zu", class_getInstanceSize([Student class]));
NSLog(@"%zu", malloc_size((__bridge const void *)student));
2020-12-16 15:34:28.133872+0800 24
2020-12-16 15:34:28.134047+0800 32

将Person 和 Student转换为结构体
// int _no

struct Person_IMPL {
    struct NSObject_IMPL NSObject_IVARS; // 8
    int _age; // 4
}

struct Student_IMPL {
    struct Person_IMPL NSObject_IVARS; // 16
    int _no; // 4
}
因为 NSObject_IVARS 只使用了 12个字节,所以还剩4个字节,直接将_age赋值过去。所以实例变量的占用内存大小是16,系统分配给对象的内存大小也是16

// double _no

struct Person_IMPL {
    struct NSObject_IMPL NSObject_IVARS; // 8
    int _age; // 4
}

struct Student_IMPL {
    struct Person_IMPL NSObject_IVARS; // 16
    double _no; // 8
}
因为 NSObject_IVARS 只使用了 12个字节,所以还剩4个字节,剩下的自己不足以分配8。又因为结构体的大小必须是最大成员大小的倍数,所以实例变量的占用内存大小是16 + 8 = 24,系统分配给对象的内存大小是 16 * 2 = 32。

四、什么是对象:

Objective-C对象是结构体
NSObject转化为C/C++代码源码:

struct NSObject_IMPL {
    Class isa; // 8个字节
};
因为alloc的时候最小分配16字节,所以系统为一个对象分配了16字节,NSObject对象仅占用8字节。

一个指针占用八个字节
一个空的Objective-C对象被创建出来占用8个字节
struct objc_object {
Class *isa;
} id;

将代码编译成c++代码:
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc "Class.m" -o "Class.cpp"

命令 解释
xcrun Xcoderun
-sdk 选择支持平台
iphoneos iphone平台
clang llvm编辑器命令
-arch 架构
arm64 模拟器(i386) 32bit(arm32) 64bit(arm64)
-rewrite-objc 重写
-o 保存到某个文件

实例对象里只放成员变量,不放方法。方法是放在类的方法列表里。

上一篇下一篇

猜你喜欢

热点阅读