12

Objective-C 对象模型和消息传递

 3 years ago
source link: http://blog.danthought.com/programming/2020/12/01/objective-c-object-and-messaging/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

本文并不是一篇完整的教程,更像一篇快速笔记,讲解 Objective-C 中的对象模型和消息传递。

Objective C

Objective-C 对象模型

Objective-C 对象的实质

Objective-C 中一切皆对象,如下的代码中,someString 是对象,NSString 是类对象。

NSString *someString = @"The string";

someString 对象会参照如下 id 定义的模版进行定义,其本质也是结构体指针:

typedef struct objc_object {
    Class isa; // 是什么类
} *id;

Class 定义是如下的类对象结构体指针:

typedef struct objc_class *Class;
struct objc_class {
    Class isa; // 是什么类
    Class super_class; // 父类
    const char *name;
    long version;
    long info;
    long instance_size;
    struct objc_ivar_list *ivars; // 实例变量
    struct objc_method_list **methodLists; // 方法列表
    struct objc_cache *cache;
    struct objc_protocol_list *protocols;
}

综合起来,类关系图如下:

Objective-C Class Hierarchy

由上图可见,类方法就是定义在 metaclass 中的实例方法。

检测类层级的方法:

- (BOOL)isKindOfClass:(Class)aClass;
- (BOOL)isMemberOfClass:(Class)aClass;

Objective-C 对象的内存分布

NSString *someString = @"The string";
NSString *anotherString = someString;

上面的代码在内存中的表示如下图:

NSString

栈中的变量在压栈出栈的时候被自动管理,堆中的内存管理被 Objective-C 做了抽象,不需要使用 开始学习 Objective-C - 动态存储分配 中描述的 C 语言的动态存储分配函数,而是 Objective-C 内存管理 中描述的自动引用计数 ARC 来管理。

Objective-C 消息传递

先来看一下 Objective-C 和 C++ 中的方法调用:

Object *obj = [Object new];
[obj performWith:parameter1 and:parameter2];
Object *obj = new Object();
obj->perform(parameter1, parameter2);

在 Objective-C 中,方法调用的本质是消息传递,都是在运行时决定那个实现代码被执行,编译器不关心被发送消息的对象类型,都是在运行时做决定。

而在 C++ 中,方法调用是在编译时决定的,Virtual Function 是通过 Virtual Table 在运行时决定那个实现代码被执行。

objc_msgSend

Object *obj = [Object new];
[obj performWith:parameter1 and:parameter2];

上面的方法调用,都会被编译器转化为 C 函数 objc_msgSend:

void objc_msgSend(id self, SEL cmd, ...)

id 就是消息的接收者,SEL 就是对方法的封装,… 就是参数值

objc_msgSend 根据 id 和 SEL 找到正确的方法然后调用,objc_msgSend 会把这个查找结果缓存起来,下次就不用找了。

动态方法解析

接着上面的说,objc_msgSend 根据 id 和 SEL 没有找到正确的方法,就会进行如下 3 步的动态方法解析:

+ (BOOL)resolveInstanceMethod:(SEL)sel;
- (id)forwardingTargetForSelector:(SEL)aSelector;
- (void)forwardInvocation:(NSInvocation *)anInvocation;

Method Swizzling

Objective-C 中的类都有一个如下列表,表示方法名到方法实现的对应:

Method Swizzling Before

经过如下代码的转换,lowercaseString 和 uppercaseString 对应实现进行了交换:

Method originalMethod = class_getInstanceMethod([NSString string], @selector(lowercaseString));
Method swappedMethod = class_getInstanceMethod([NSString string], @selector(uppercaseString));

method_exchangeImplementations(originalMethod, swappedMethod);
Method Swizzling After

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK