1. 前言

[重学技术]系列主要是针对笔者自己的能力进行的针对性学习,不代表广大读者的情况。

带着问题出发

  • 什么是 NSObject
  • NSObject 的本质

2. 正文

1.以代码开始

1
2
3
4
5
6
7
8
9
10
11
12
13
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
@autoreleasepool {
NSObject *p = [[NSObject alloc] init];
NSLog(@"%lu", sizeof(p)); // 8
NSLog(@"%lu", sizeof(&p)); // 8
NSLog(@"%lu", sizeof(p.class)); // 8
NSLog(@"%lu", sizeof(NSObject.class)); // 8
NSLog(@"%lu", sizeof(struct objc_object)); // 8
NSLog(@"%lu", class_getInstanceSize(p.class)); // 8
NSLog(@"%lu", malloc_size((__bridge const void *)(p))); // 16
}
}

这里可以看出 p 指针指向一块内存区域,&p 即是 NSObject 的一个实例对象的所在的地址。
在M2机器下,一个指针大小为8字节,所以sizeof(p) = 8。
NSObject = struct objc_object { struct objc_class *isa; } 占用一个指针 = 8。
p.class = NSObject = 8
NSObject.class = 元类 = { struct objc_class *isa; } 占用一个指针 = 8。
通过class_getInstanceSize的结果对比malloc_size,class_getInstanceSize表示实际可用的的内存空间大小,malloc_size表示为实例分配的内存的大小,由于该实例内部存储一个isa指针,已经占用了8字节,同时为了保证16位对其,分配了16位的整数倍内存空间。从而导致,填充了8字节的0。
SO!
class_getInstanceSize的结果就是除了isa指针占用之外的内存大小(16 - isa(8) = 8)。
malloc_size的结果是实例占用的全部内存大小(16)。

2.一行指令

1
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc {源文件} [-o] [{目标文件}]

3.三段代码

1.主函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// ...
// Foundation头文件展开的部分 超多行
// ...
#define XXX XXX
int main(int argc, char *argv[]) {
/* @autoreleasepool */
{ __AtAutoreleasePool __autoreleasepool;
NSObject *p = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)(
(id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)(
(id)objc_getClass("NSObject"),
sel_registerName("alloc")
),
sel_registerName("init")
);
NSLog((NSString *)&0, sizeof(p)); // 指针类型 = 8
NSLog((NSString *)&XXX1, sizeof(&p)); // 指针类型 = 8
NSLog((NSString *)&XXX2, sizeof((Class (*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("class"))); // Class = struct objc_class * 指针类型 = 8
NSLog((NSString *)&XXX3, sizeof((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("class"))); // Class = struct objc_class * 指针类型 = 8
NSLog((NSString *)&XXX4, sizeof(struct objc_object)); // struct objc_object 包含ias指针 = 8
NSLog((NSString *)&XXX5, class_getInstanceSize(((Class (*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("class")))); // word_align(unalignedInstanceSize()) = 8
NSLog((NSString *)&XXX6, malloc_size((__bridge const void *)(p))); // isa + +ivar + 填充 = 16位对齐
}
}
// ...

2.需要关注的部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14

typedef struct objc_object NSObject; // NSObject

struct NSObject_IMPL {
Class isa;
};

typedef struct objc_class *Class; // Class
typedef struct objc_object *id; // id
typedef struct objc_selector *SEL; // SEL

typedef void (*IMP)(void); // IMP
typedef bool BOOL; // BOOL

NSObject_IMPL == NSObject 一个实例对应的结构,所有实例对象的操作都是通过 isa 指针操作
类对象 + 元类对象 = NSObject

3.关键方法

1
2
3
4
5
6
7
8
9
10
objc_msgSend(id, SEL) 
objc_getClass(const char *name) {
// ① OC类
result = getClassExceptSomeSwift + realizeClassMaybeSwiftAndUnlock
// ② Swift类
look_up_class -> for(tls = _objc_fetch_pthread_data) -> may be nil
result = swiftcls = GetClassHook

}
sel_registerName(const char *name)

拆分结构后比较清晰,它们分别完成一些任务

- objc_msgSend(id, SEL, ...) 负责消息发送,传入接收方、方法、参数。汇编实现
- objc_getClass(const char *name) 负责通过类名获取类对象
- sel_registerName(const char *name) 负责通过方法名拿到方法

4.分析

1.NSObject

从源码的NSObject.h,NSObject.mm,objc-object.h,objc-private.h,objc-runtime-new.h看,关键是_objc_, object_, class_开头的核心方法以及内部的结构体|类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
@implementation NSObject

+ (void)initialize {
}

// 类对象本身
+ (id)self {
return (id)self;
}

// 实例对象本身
- (id)self {
return self;
}

// 获取类对象
+ (Class)class {
return self;
}

// 实例方法,获取实例的,类对象
- (Class)class {
return object_getClass(self);
}

// 类方法,获取当前类的,父类对象
+ (Class)superclass {
return self->getSuperclass();
}

// 实例方法,获取当前实例的,父类对象
- (Class)superclass {
return [self class]->getSuperclass();
}

// 类方法,判断当前类对象,是不是cls
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}

// 实例方法,判断当前实例,是不是cls的实例
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}

// 类方法,判断当前类对象,是不是cls的子类对象
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = self->ISA(); tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}

// 实例方法,判断当前实例,是不是cls的子类对象的实例
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}

// 类方法,判断当前类对象,是不是cls的子类对象
+ (BOOL)isSubclassOfClass:(Class)cls {
for (Class tcls = self; tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}

// 类方法,判断当前类对象,是不是obj的父类对象
+ (BOOL)isAncestorOfObject:(NSObject *)obj {
for (Class tcls = [obj class]; tcls; tcls = tcls->getSuperclass()) {
if (tcls == self) return YES;
}
return NO;
}

// 类方法 (实例 方法 相应的类对象)
+ (BOOL)instancesRespondToSelector:(SEL)sel {
return class_respondsToSelector_inst(nil, sel, self);
}

// 类方法 (实例 方法 相应的类对象)
+ (BOOL)respondsToSelector:(SEL)sel {
return class_respondsToSelector_inst(self, sel, self->ISA());
}

// 类方法 (实例 方法 相应的类对象)
- (BOOL)respondsToSelector:(SEL)sel {
return class_respondsToSelector_inst(self, sel, [self class]);
}

// 类方法,判断当前类对象,是否遵循某个协议
+ (BOOL)conformsToProtocol:(Protocol *)protocol {
if (!protocol) return NO;
for (Class tcls = self; tcls; tcls = tcls->getSuperclass()) {
if (class_conformsToProtocol(tcls, protocol)) return YES;
}
return NO;
}

// 类方法,判断当前实例,是否遵循某个协议
- (BOOL)conformsToProtocol:(Protocol *)protocol {
if (!protocol) return NO;
for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) {
if (class_conformsToProtocol(tcls, protocol)) return YES;
}
return NO;
}

// 类对象哈希
+ (NSUInteger)hash {
return _objc_rootHash(self);
}

// 实例哈希
- (NSUInteger)hash {
return _objc_rootHash(self);
}

// 类对象是否相等(指针维度)
+ (BOOL)isEqual:(id)obj {
return obj == (id)self;
}

// 实例是否相等(指针维度)
- (BOOL)isEqual:(id)obj {
return obj == self;
}

// ??? override point
+ (BOOL)isFault {
return NO;
}

// ??? override point
- (BOOL)isFault {
return NO;
}

// 是否代理 override point
+ (BOOL)isProxy {
return NO;
}

// 是否代理 override point
- (BOOL)isProxy {
return NO;
}

// 类方法,SEL -> IMP 查询
+ (IMP)instanceMethodForSelector:(SEL)sel {
if (!sel) [self doesNotRecognizeSelector:sel];
return class_getMethodImplementation(self, sel);
}

// 由于object_getMethodImplementation包装了class_getMethodImplementation
IMP object_getMethodImplementation(id obj, SEL name) {
Class cls = (obj ? obj->getIsa() : nil);
return class_getMethodImplementation(cls, name);
}

// 类方法,SEL -> IMP 查询
+ (IMP)methodForSelector:(SEL)sel {
if (!sel) [self doesNotRecognizeSelector:sel];
return object_getMethodImplementation((id)self, sel);
}

// 实例方法,SEL -> IMP 查询
- (IMP)methodForSelector:(SEL)sel {
if (!sel) [self doesNotRecognizeSelector:sel];
return object_getMethodImplementation(self, sel);
}

// 动态方法解析第一环 当前对象处理
+ (BOOL)resolveClassMethod:(SEL)sel {
return NO;
}

// 动态方法解析第一环 当前对象处理
+ (BOOL)resolveInstanceMethod:(SEL)sel {
return NO;
}

// 动态方法解析最终崩溃点
// Replaced by CF (throws an NSException)
+ (void)doesNotRecognizeSelector:(SEL)sel {
_objc_fatal("+[%s %s]: unrecognized selector sent to instance %p",
class_getName(self), sel_getName(sel), self);
}

// 动态方法解析最终崩溃点
// Replaced by CF (throws an NSException)
- (void)doesNotRecognizeSelector:(SEL)sel {
_objc_fatal("-[%s %s]: unrecognized selector sent to instance %p",
object_getClassName(self), sel_getName(sel), self);
}

// 动态调用类方法
+ (id)performSelector:(SEL)sel {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL))objc_msgSend)((id)self, sel);
}
+ (id)performSelector:(SEL)sel withObject:(id)obj {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL, id))objc_msgSend)((id)self, sel, obj);
}
+ (id)performSelector:(SEL)sel withObject:(id)obj1 withObject:(id)obj2 {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL, id, id))objc_msgSend)((id)self, sel, obj1, obj2);
}

// 动态调用实例方法
- (id)performSelector:(SEL)sel {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL))objc_msgSend)(self, sel);
}
- (id)performSelector:(SEL)sel withObject:(id)obj {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL, id))objc_msgSend)(self, sel, obj);
}
- (id)performSelector:(SEL)sel withObject:(id)obj1 withObject:(id)obj2 {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL, id, id))objc_msgSend)(self, sel, obj1, obj2);
}

// 动态方法解析第三环 签名
// Replaced by CF (returns an NSMethodSignature)
+ (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)sel {
_objc_fatal("+[NSObject instanceMethodSignatureForSelector:] "
"not available without CoreFoundation");
}

// 动态方法解析第三环 签名
// Replaced by CF (returns an NSMethodSignature)
+ (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
_objc_fatal("+[NSObject methodSignatureForSelector:] "
"not available without CoreFoundation");
}
// Replaced by CF (returns an NSMethodSignature)
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
_objc_fatal("-[NSObject methodSignatureForSelector:] "
"not available without CoreFoundation");
}

// 动态方法解析第三环 完整消息转发
+ (void)forwardInvocation:(NSInvocation *)invocation {
[self doesNotRecognizeSelector:(invocation ? [invocation selector] : 0)];
}

// 动态方法解析第三环 完整消息转发
- (void)forwardInvocation:(NSInvocation *)invocation {
[self doesNotRecognizeSelector:(invocation ? [invocation selector] : 0)];
}

// 动态方法解析第二环 快速消息转发 转发给另一个对象
+ (id)forwardingTargetForSelector:(SEL)sel {
return nil;
}

// 动态方法解析第二环 快速消息转发 转发给另一个对象
- (id)forwardingTargetForSelector:(SEL)sel {
return nil;
}

// 类对象描述 override point
// Replaced by CF (returns an NSString)
+ (NSString *)description {
return nil;
}
+ (NSString *)debugDescription {
return [self description];
}

// 实例对象描述 override point
// Replaced by CF (returns an NSString)
- (NSString *)description {
return nil;
}
- (NSString *)debugDescription {
return [self description];
}

// 1.对象的出生
+ (id)new {
return [callAlloc(self, false/*checkNil*/) init];
}
+ (id)alloc {
return _objc_rootAlloc(self);
}
// Replaced by ObjectAlloc
+ (id)allocWithZone:(struct _NSZone *)zone {
return _objc_rootAllocWithZone(self, (objc_zone_t)zone);
}
// Replaced by CF (throws an NSException)
+ (id)init {
return (id)self;
}
- (id)init {
return _objc_rootInit(self);
}

// 2.引用计数
+ (id)retain {
return (id)self;
}
+ (BOOL)_tryRetain {
return YES;
}
+ (NSUInteger)retainCount {
return ULONG_MAX;
}
// Replaced by ObjectAlloc
- (id)retain {
return _objc_rootRetain(self);
}
// Replaced by ObjectAlloc
- (BOOL)_tryRetain {
return _objc_rootTryRetain(self);
}
- (NSUInteger)retainCount {
return _objc_rootRetainCount(self);
}
// 弱引用
+ (BOOL)allowsWeakReference {
return YES;
}
+ (BOOL)retainWeakReference {
return YES;
}
- (BOOL)allowsWeakReference {
return ! [self _isDeallocating];
}
- (BOOL)retainWeakReference {
return [self _tryRetain];
}

// 3.存活空间
+ (struct _NSZone *)zone {
return (struct _NSZone *)_objc_rootZone(self);
}
- (struct _NSZone *)zone {
return (struct _NSZone *)_objc_rootZone(self);
}

// 4.续命
+ (id)copy {
return (id)self;
}
+ (id)copyWithZone:(struct _NSZone *)zone {
return (id)self;
}
- (id)copy {
return [(id)self copyWithZone:nil];
}
+ (id)mutableCopy {
return (id)self;
}
+ (id)mutableCopyWithZone:(struct _NSZone *)zone {
return (id)self;
}
- (id)mutableCopy {
return [(id)self mutableCopyWithZone:nil];
}

// 5.对象的消亡
+ (id)autorelease {
return (id)self;
}
// Replaced by ObjectAlloc
- (id)autorelease {
return _objc_rootAutorelease(self);
}
+ (oneway void)release {
}
// Replaced by ObjectAlloc
- (oneway void)release {
_objc_rootRelease(self);
}
// Replaced by CF (throws an NSException)
+ (void)dealloc {
}
// Replaced by NSZombies
- (void)dealloc {
_objc_rootDealloc(self);
}
+ (BOOL)_isDeallocating {
return NO;
}
- (BOOL)_isDeallocating {
return _objc_rootIsDeallocating(self);
}

// Previously used by GC. Now a placeholder for binary compatibility.
- (void) finalize { }

2.objc_object

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// objc-private.h
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};

struct objc_object {
private:
char isa_storage[sizeof(isa_t)];

isa_t &isa() { return *reinterpret_cast<isa_t *>(isa_storage); }
const isa_t &isa() const { return *reinterpret_cast<const isa_t *>(isa_storage); }

public:

// ISA() assumes this is NOT a tagged pointer object
Class ISA(bool authenticated = false);

// rawISA() assumes this is NOT a tagged pointer object or a non pointer ISA
Class rawISA();

// getIsa() allows this to be a tagged pointer object
Class getIsa();

uintptr_t isaBits() const;

// initIsa() should be used to init the isa of new objects only.
// If this object already has an isa, use changeIsa() for correctness.
// initInstanceIsa(): objects with no custom RR/AWZ
// initClassIsa(): class objects
// initProtocolIsa(): protocol objects
// initIsa(): other objects
void initIsa(Class cls /*nonpointer=false*/);
void initClassIsa(Class cls /*nonpointer=maybe*/);
void initProtocolIsa(Class cls /*nonpointer=maybe*/);
void initInstanceIsa(Class cls, bool hasCxxDtor);

// changeIsa() should be used to change the isa of existing objects.
// If this is a new object, use initIsa() for performance.
Class changeIsa(Class newCls);

bool hasNonpointerIsa();
bool isTaggedPointer();
bool isBasicTaggedPointer();
bool isExtTaggedPointer();
bool isClass();

// object may have associated objects?
bool hasAssociatedObjects();
void setHasAssociatedObjects();

// object may be weakly referenced?
bool isWeaklyReferenced();
void setWeaklyReferenced_nolock();

// object may be uniquely referenced?
bool isUniquelyReferenced();

// object may have -.cxx_destruct implementation?
bool hasCxxDtor();

// Optimized calls to retain/release methods
id retain();
void release();
id autorelease();

// Implementations of retain/release methods
id rootRetain();
bool rootRelease();
id rootAutorelease();
bool rootTryRetain();
bool rootReleaseShouldDealloc();
uintptr_t rootRetainCount();

// Implementation of dealloc methods
bool rootIsDeallocating();
void clearDeallocating();
void rootDealloc();

private:
void initIsa(Class newCls, bool nonpointer, bool hasCxxDtor);

// Slow paths for inline control
id rootAutorelease2();

#if SUPPORT_NONPOINTER_ISA
// Controls what parts of root{Retain,Release} to emit/inline
// - Full means the full (slow) implementation
// - Fast means the fastpaths only
// - FastOrMsgSend means the fastpaths but checking whether we should call
// -retain/-release or Swift, for the usage of objc_{retain,release}
enum class RRVariant {
Full,
Fast,
FastOrMsgSend,
};

// Unified retain count manipulation for nonpointer isa
inline id rootRetain(bool tryRetain, RRVariant variant);
inline bool rootRelease(bool performDealloc, RRVariant variant);
id rootRetain_overflow(bool tryRetain);
uintptr_t rootRelease_underflow(bool performDealloc);

void clearDeallocating_slow();

// Side table retain count overflow for nonpointer isa
struct SidetableBorrow { size_t borrowed, remaining; };

void sidetable_lock();
void sidetable_unlock();

void sidetable_moveExtraRC_nolock(size_t extra_rc, bool isDeallocating, bool weaklyReferenced);
bool sidetable_addExtraRC_nolock(size_t delta_rc);
SidetableBorrow sidetable_subExtraRC_nolock(size_t delta_rc);
size_t sidetable_getExtraRC_nolock();
void sidetable_clearExtraRC_nolock();
#endif

// Side-table-only retain count
bool sidetable_isDeallocating();
void sidetable_clearDeallocating();

bool sidetable_isWeaklyReferenced();
void sidetable_setWeaklyReferenced_nolock();

id sidetable_retain(bool locked = false);
id sidetable_retain_slow(SideTable& table);

uintptr_t sidetable_release(bool locked = false, bool performDealloc = true);
uintptr_t sidetable_release_slow(SideTable& table, bool performDealloc = true);

bool sidetable_tryRetain();

uintptr_t sidetable_retainCount();
#if DEBUG
bool sidetable_present();
#endif

void performDealloc();
};

3.objc_class: objc_object

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
// objc-runtime-new.h
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

Class getSuperclass() const {
#if __has_feature(ptrauth_calls)
# if ISA_SIGNING_AUTH_MODE == ISA_SIGNING_AUTH
if (superclass == Nil)
return Nil;

#if SUPERCLASS_SIGNING_TREAT_UNSIGNED_AS_NIL
void *stripped = ptrauth_strip((void *)superclass, ISA_SIGNING_KEY);
if ((void *)superclass == stripped) {
void *resigned = ptrauth_sign_unauthenticated(stripped, ISA_SIGNING_KEY, ptrauth_blend_discriminator(&superclass, ISA_SIGNING_DISCRIMINATOR_CLASS_SUPERCLASS));
if ((void *)superclass != resigned)
return Nil;
}
#endif

void *result = ptrauth_auth_data((void *)superclass, ISA_SIGNING_KEY, ptrauth_blend_discriminator(&superclass, ISA_SIGNING_DISCRIMINATOR_CLASS_SUPERCLASS));
return (Class)result;

# else
return (Class)ptrauth_strip((void *)superclass, ISA_SIGNING_KEY);
# endif
#else
return superclass;
#endif
}

void setSuperclass(Class newSuperclass) {
#if ISA_SIGNING_SIGN_MODE == ISA_SIGNING_SIGN_ALL
superclass = (Class)ptrauth_sign_unauthenticated((void *)newSuperclass, ISA_SIGNING_KEY, ptrauth_blend_discriminator(&superclass, ISA_SIGNING_DISCRIMINATOR_CLASS_SUPERCLASS));
#else
superclass = newSuperclass;
#endif
}

class_rw_t *data() const {
return bits.data();
}
void setData(class_rw_t *newData) {
bits.setData(newData);
}

const class_ro_t *safe_ro() const {
return bits.safe_ro();
}

void setInfo(uint32_t set) {
ASSERT(isFuture() || isRealized());
data()->setFlags(set);
}

void clearInfo(uint32_t clear) {
ASSERT(isFuture() || isRealized());
data()->clearFlags(clear);
}

// set and clear must not overlap
void changeInfo(uint32_t set, uint32_t clear) {
ASSERT(isFuture() || isRealized());
ASSERT((set & clear) == 0);
data()->changeFlags(set, clear);
}

// ...

bool canAllocNonpointer() {
ASSERT(!isFuture());
return !instancesRequireRawIsa();
}

bool isSwiftStable() {
return bits.isSwiftStable();
}

bool isSwiftLegacy() {
return bits.isSwiftLegacy();
}

bool isAnySwift() {
return bits.isAnySwift();
}

bool isSwiftStable_ButAllowLegacyForNow() {
return bits.isSwiftStable_ButAllowLegacyForNow();
}

uint32_t swiftClassFlags() {
return *(uint32_t *)(&bits + 1);
}

bool usesSwiftRefcounting() {
if (!isSwiftStable()) return false;
return bool(swiftClassFlags() & 2); //ClassFlags::UsesSwiftRefcounting
}

bool canCallSwiftRR() {
// !hasCustomCore() is being used as a proxy for isInitialized(). All
// classes with Swift refcounting are !hasCustomCore() (unless there are
// category or swizzling shenanigans), but that bit is not set until a
// class is initialized. Checking isInitialized requires an extra
// indirection that we want to avoid on RR fast paths.
//
// In the unlikely event that someone causes a class with Swift
// refcounting to be hasCustomCore(), we'll fall back to sending -retain
// or -release, which is still correct.
return !hasCustomCore() && usesSwiftRefcounting();
}

bool isStubClass() const {
uintptr_t isa = (uintptr_t)isaBits();
return 1 <= isa && isa < 16;
}

// Swift stable ABI built for old deployment targets looks weird.
// The is-legacy bit is set for compatibility with old libobjc.
// We are on a "new" deployment target so we need to rewrite that bit.
// These stable-with-legacy-bit classes are distinguished from real
// legacy classes using another bit in the Swift data
// (ClassFlags::IsSwiftPreStableABI)

bool isUnfixedBackwardDeployingStableSwift() {
// Only classes marked as Swift legacy need apply.
if (!bits.isSwiftLegacy()) return false;

// Check the true legacy vs stable distinguisher.
// The low bit of Swift's ClassFlags is SET for true legacy
// and UNSET for stable pretending to be legacy.
bool isActuallySwiftLegacy = bool(swiftClassFlags() & 1);
return !isActuallySwiftLegacy;
}

void fixupBackwardDeployingStableSwift() {
if (isUnfixedBackwardDeployingStableSwift()) {
// Class really is stable Swift, pretending to be pre-stable.
// Fix its lie.

// N.B. At this point, bits is *always* a class_ro pointer; we
// can't use setIsSwiftStable() because that only works for a
// class_rw pointer.
bits.setIsSwiftStableRO();
}
}

_objc_swiftMetadataInitializer swiftMetadataInitializer() {
return bits.swiftMetadataInitializer();
}

// Return YES if the class's ivars are managed by ARC,
// or the class is MRC but has ARC-style weak ivars.
bool hasAutomaticIvars() {
return data()->ro()->flags & (RO_IS_ARC | RO_HAS_WEAK_WITHOUT_ARC);
}

// Return YES if the class's ivars are managed by ARC.
bool isARC() {
return data()->ro()->flags & RO_IS_ARC;
}


bool forbidsAssociatedObjects() {
return (data()->flags & RW_FORBIDS_ASSOCIATED_OBJECTS);
}

#if SUPPORT_NONPOINTER_ISA
// Tracked in non-pointer isas; not tracked otherwise
#else
bool instancesHaveAssociatedObjects() {
// this may be an unrealized future class in the CF-bridged case
ASSERT(isFuture() || isRealized());
return data()->flags & RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS;
}

void setInstancesHaveAssociatedObjects() {
// this may be an unrealized future class in the CF-bridged case
ASSERT(isFuture() || isRealized());
setInfo(RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS);
}
#endif

bool shouldGrowCache() {
return true;
}

void setShouldGrowCache(bool) {
// fixme good or bad for memory use?
}

bool isInitializing() {
return getMeta()->bits.flags() & RW_INITIALIZING;
}

void setInitializing() {
ASSERT(!isMetaClass());
ISA()->setInfo(RW_INITIALIZING);
}

bool isInitialized() {
return getMeta()->bits.flags() & RW_INITIALIZED;
}

void setInitialized();

bool isLoadable() {
ASSERT(isRealized());
return true; // any class registered for +load is definitely loadable
}

IMP getLoadMethod();

// Locking: To prevent concurrent realization, hold runtimeLock.
bool isRealized() const {
return !isStubClass() && (bits.flags() & RW_REALIZED);
}

// Returns true if this is an unrealized future class.
// Locking: To prevent concurrent realization, hold runtimeLock.
bool isFuture() const {
if (isStubClass())
return false;
return bits.flags() & RW_FUTURE;
}

bool isMetaClass() const {
ASSERT_THIS_NOT_NULL;
ASSERT(isRealized());
#if FAST_CACHE_META
return cache.getBit(FAST_CACHE_META);
#else
return data()->flags & RW_META;
#endif
}

// Like isMetaClass, but also valid on un-realized classes
bool isMetaClassMaybeUnrealized() {
static_assert(offsetof(class_rw_t, flags) == offsetof(class_ro_t, flags), "flags alias");
static_assert(RO_META == RW_META, "flags alias");
if (isStubClass())
return false;
return bits.flags() & RW_META;
}

// NOT identical to this->ISA when this is a metaclass
Class getMeta() {
if (isMetaClassMaybeUnrealized()) return (Class)this;
else return this->ISA();
}

bool isRootClass() {
return getSuperclass() == nil;
}
bool isRootMetaclass() {
return ISA() == (Class)this;
}

// If this class does not have a name already, we can ask Swift to construct one for us.
const char *installMangledNameForLazilyNamedClass();

// Get the class's mangled name, or NULL if the class has a lazy
// name that hasn't been created yet.
const char *nonlazyMangledName() const {
return bits.safe_ro()->getName();
}

const char *mangledName() {
// fixme can't assert locks here
ASSERT_THIS_NOT_NULL;

const char *result = nonlazyMangledName();

if (!result) {
// This class lazily instantiates its name. Emplace and
// return it.
result = installMangledNameForLazilyNamedClass();
}

return result;
}

// Get the class's mangled name, or NULL if it has a lazy name that hasn't
// been created yet, WITHOUT authenticating the signed class_ro pointer.
// This exists sosely for objc_debug_class_getNameRaw to use.
const char *rawUnsafeMangledName() const {
// Strip the class_ro pointer instead of authenticating so that we can
// handle classes without signed class_ro pointers in the shared cache
// even if they haven't been officially loaded yet. rdar://90415774
return bits.safe_ro<Authentication::Strip>()->getName();
}

const char *demangledName(bool needsLock);
const char *nameForLogging();

// May be unaligned depending on class's ivars.
uint32_t unalignedInstanceStart() const {
ASSERT(isRealized());
return data()->ro()->instanceStart;
}

// Class's instance start rounded up to a pointer-size boundary.
// This is used for ARC layout bitmaps.
uint32_t alignedInstanceStart() const {
return word_align(unalignedInstanceStart());
}

// May be unaligned depending on class's ivars.
uint32_t unalignedInstanceSize() const {
ASSERT(isRealized());
return data()->ro()->instanceSize;
}

// Class's ivar size rounded up to a pointer-size boundary.
uint32_t alignedInstanceSize() const {
return word_align(unalignedInstanceSize());
}

inline size_t instanceSize(size_t extraBytes) const {
if (fastpath(cache.hasFastInstanceSize(extraBytes))) {
return cache.fastInstanceSize(extraBytes);
}

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

void setInstanceSize(uint32_t newSize) {
ASSERT(isRealized());
ASSERT(data()->flags & RW_REALIZING);
auto ro = data()->ro();
if (newSize != ro->instanceSize) {
ASSERT(data()->flags & RW_COPIED_RO);
*const_cast<uint32_t *>(&ro->instanceSize) = newSize;
}
cache.setFastInstanceSize(newSize);
}

void chooseClassArrayIndex();

void setClassArrayIndex(unsigned Idx) {
bits.setClassArrayIndex(Idx);
}

unsigned classArrayIndex() {
return bits.classArrayIndex();
}
};

4.其他结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// objc-runtime-new.h
struct bucket_t {}
struct preopt_cache_t {}
struct RelativePointer: nocopy_t {}
struct stub_class_t {}

struct cache_t {}
struct method_t {}
struct ivar_t {}
struct property_t {}

struct entsize_list_tt {} // 模板
struct method_list_t: entsize_list_tt {}
struct protocol_t : objc_object {}
struct protocol_list_t {}

struct class_ro_t {}
struct class_rw_t {}
struct class_data_bits_t {}


class list_array_tt {} // 模板
class method_array_t: list_array_tt {}
class property_array_t: list_array_tt {}
class protocol_array_t: list_array_tt {}

struct swift_class_t: objc_class {}

struct category_t {}

5.一切皆对象

从源码可以看到 objc_class 继承自 objc_object,从而具有了对象的能力。
可以看到 NSObject_IMPL 中 isa 作为 Class 类型,本质上指向了自己对应的 objc_class 类型的类对象。
同时 objc_class 中 isa 作为 Class 类型,指向了类对象所对应的元类对象。

instance.isa -n-> 类对象.isa -1-> 元类对象.isa -> 根元类对象。
从设计者角度来看,类对象会占用空间,但是不需要存储多份,把变化的部分(状态:实例变量)外置,运行时存储到堆栈;而不变的部分(行为:实例方法)内置,保存在一个全局访问的位置,所以可以认为类对象为实例提供了原型,通过 isa 连接。
元类对象同样会占用空间,同样不需要存储多份,把变化的部分(状态:类变量)外置,运行时存储到全局区域;而不变的部分(行为:类方法)内置,保存在一个全局访问的位置,同样认为元类对象为类对象提供了原型,通过 isa 连接。

6.代码中出现的方法

1.[oc 语言层面]
_objc_rootHash
_objc_fatal

_objc_rootAlloc
_objc_rootInit { return obj; // do nothing }
_objc_rootRetain
_objc_rootTryRetain { return rootRetain(tryRetain, RRVariant::Fast) }
_objc_rootRetainCount
_objc_rootZone

_objc_rootAutorelease
_objc_rootRelease
_objc_rootDealloc
_objc_rootIsDeallocating

2.[class 类层面]
class_respondsToSelector_inst
class_conformsToProtocol
class_getMethodImplementation
class_getName

3.[object 实例层面]
object_getClass
object_getMethodImplementation
object_getClassName

4.[SEL 方法层面]
sel_getName
sel_registerName

7.各个击破

1._objc_rootHash

1
2
3
4
5
6
7
// NSObject.mm
// 本质是对象指针的整形值
typedef unsigned long
uintptr_t _objc_rootHash(id obj)
{
return (uintptr_t)obj;
}

2._objc_fatal 致命错误 logs -> print —> abort -> terminate + trap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// objc-os.h
extern void _objc_fatal(const char *fmt, ...)
__attribute__((noreturn, cold, format (printf, 1, 2)));
extern void _objc_fatal_with_reason(uint64_t reason, uint64_t flags,
const char *fmt, ...)
__attribute__((noreturn, cold, format (printf, 3, 4)));

// objc-errors.mm
/*
* this routine handles severe runtime errors...like not being able
* to read the mach headers, allocate space, etc...very uncommon.
*/
void _objc_fatal(const char *fmt, ...)
{
va_list ap;
va_start(ap,fmt);
_objc_fatalv(OBJC_EXIT_REASON_UNSPECIFIED,
OS_REASON_FLAG_ONE_TIME_FAILURE,
fmt, ap);
}
void _objc_fatalv(uint64_t reason, uint64_t flags, const char *fmt, va_list ap)
{
char *buf1;
_objc_vasprintf(&buf1, fmt, ap);

char *buf2;
_objc_asprintf(&buf2, "objc[%d]: %s\n", getpid(), buf1);
_objc_syslog(buf2);

if (DebugDontCrash) {
char *buf3;
_objc_asprintf(&buf3, "objc[%d]: HALTED\n", getpid());
_objc_syslog(buf3);
_Exit(1);
}
else {
_objc_crashlog(buf1);
abort_with_reason(OS_REASON_OBJC, reason, buf1, flags);
}
}

// xnu/libsyscall
void
abort_with_reason(uint32_t reason_namespace, uint64_t reason_code, const char *reason_string,
uint64_t reason_flags)
{
abort_with_payload_wrapper_internal(reason_namespace, reason_code, 0, 0, reason_string, reason_flags);
}
static void abort_with_payload_wrapper_internal(uint32_t reason_namespace, uint64_t reason_code,
void *payload, uint32_t payload_size, const char *reason_string,
uint64_t reason_flags)
{
sigset_t unmask_signal;

/* Try to unmask SIGABRT before trapping to the kernel */
sigemptyset(&unmask_signal);
sigaddset(&unmask_signal, SIGABRT);
sigprocmask(SIG_UNBLOCK, &unmask_signal, NULL);

__abort_with_payload(reason_namespace, reason_code, payload, payload_size,
reason_string, reason_flags);

/* If sending a SIGABRT failed, we try to fall back to SIGKILL */
terminate_with_payload(getpid(), reason_namespace, reason_code, payload, payload_size,
reason_string, reason_flags);

/* Last resort, let's use SIGTRAP (SIGILL on i386) */
sigemptyset(&unmask_signal);
sigaddset(&unmask_signal, SIGTRAP);
sigaddset(&unmask_signal, SIGILL);
sigprocmask(SIG_UNBLOCK, &unmask_signal, NULL);

__builtin_trap();
}

3._objc_rootAlloc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// NSObject.mm
id _objc_rootAlloc(Class cls) {
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
// 初步分流
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false) {
if (slowpath(checkNil && !cls)) return nil; // ① 校验
if (fastpath(!cls->ISA()->hasCustomAWZ())) { // ② 判断是否有自定义的 allocWithZone
return _objc_rootAllocWithZone(cls, nil);
}

// No shortcuts available.
if (allocWithZone) {
return ((id(*)(id, SEL, struct _NSZone *))objc_msgSend)(cls, @selector(allocWithZone:), nil);
}
return ((id(*)(id, SEL))objc_msgSend)(cls, @selector(alloc));
}
// allocWithZone -> _objc_rootAllocWithZone
NEVER_INLINE
id
_objc_rootAllocWithZone(Class cls, objc_zone_t) {
// allocWithZone under __OBJC2__ ignores the zone parameter objc2忽略zone参数
return _class_createInstanceFromZone(cls, 0, nil, OBJECT_CONSTRUCT_CALL_BADALLOC);
}

// 核心方法 _class_createInstance
static ALWAYS_INLINE id
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
int construct_flags = OBJECT_CONSTRUCT_NONE,
bool cxxConstruct = true,
size_t *outAllocatedSize = nil) {
ASSERT(cls->isRealized()); // ① 校验 类对象是否已经实例化

// ② 判断 不太懂? 不影响主流程
// Read class's info bits all at once for performance
bool hasCxxCtor = cxxConstruct && cls->hasCxxCtor();
bool hasCxxDtor = cls->hasCxxDtor();
bool fast = cls->canAllocNonpointer();

size_t size;

size = cls->instanceSize(extraBytes); // ③ 计算实例对象的size
{
inline size_t instanceSize(size_t extraBytes) const {
if (fastpath(cache.hasFastInstanceSize(extraBytes))) { // 缓存
return cache.fastInstanceSize(extraBytes);
}

size_t size = alignedInstanceSize() + extraBytes; // 计算
{
uint32_t alignedInstanceSize() const {
return word_align(unalignedInstanceSize()); {
static inline uint32_t word_align(uint32_t x) {
return (x + WORD_MASK) & ~WORD_MASK;
}
uint32_t unalignedInstanceSize() const {
ASSERT(isRealized());
return data()->ro()->instanceSize; // 这个值是怎么来的? 临时记录下
{
// dyld加载流程
objc_allocateClassPair {
...
cls = alloc_class_for_subclass(superclass, extraBytes);
meta = alloc_class_for_subclass(superclass, extraBytes);
objc_initializeClassPair_internal {
...
cls->setInstanceSize(cls_ro_w->instanceStart);
meta->setInstanceSize(meta_ro_w->instanceStart);
}
...
}
...
class_addIvar
...
objc_registerClassPair
}
}
}
}
}
// CF requires all objects be at least 16 bytes.
if (size < 16) size = 16; // 不满16字节 补满
return size;
}
}
if (outAllocatedSize) *outAllocatedSize = size;

// ③ 根据size 分配内存
id obj;
#if SUPPORT_ZONES
if (zone) {
obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
} else {
#endif
obj = (id)calloc(1, size);
#if SUPPORT_ZONES
}
#endif
if (slowpath(!obj)) {
if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
return _objc_callBadAllocHandler(cls);
}
return nil;
}

// ④ 初始化isa
if (!zone && fast) {
obj->initInstanceIsa(cls, hasCxxDtor);
{
initIsa(cls, true, hasCxxDtor);
}
} else {
// Use raw pointer isa on the assumption that they might be
// doing something weird with the zone or RR.
obj->initIsa(cls);
{
initIsa(cls, false, false);
}
}

if (fastpath(!hasCxxCtor)) {
return obj;
}

// ⑤ 递归调用C++构造对象
construct_flags |= OBJECT_CONSTRUCT_FREE_ONFAILURE;
return object_cxxConstructFromClass(obj, cls, construct_flags); {
继承链向上尾递归 {
ctor = (id(*)(id))lookupMethodInClassAndLoadCache(cls, SEL_cxx_construct);
if (fastpath((*ctor)(obj))) return obj; // ctor called and succeeded - ok
// This class's ctor was called and failed.
// Call superclasses's dtors to clean up.
if (supercls) object_cxxDestructFromClass(obj, supercls);
if (flags & OBJECT_CONSTRUCT_FREE_ONFAILURE) free(obj);
if (flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
return _objc_callBadAllocHandler(cls);
}
return nil;
}
}

// ⑥ 结束 返回对象obj地址
}

4._objc_rootRetain

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// NSObject.mm
NEVER_INLINE id
_objc_rootRetain(id obj) {
ASSERT(obj);
return obj->rootRetain();
}
// objc-object.h
ALWAYS_INLINE id
objc_object::rootRetain()
{
return rootRetain(false, RRVariant::Fast); // 核心引用计数
{
do {
uintptr_t carry;
newisa.bits = addc(newisa.bits, RC_ONE, 0, &carry); // extra_rc++
if (slowpath(!newisa.nonpointer)) {
ClearExclusive(&isa().bits);
if (tryRetain) return sidetable_tryRetain() ? (id)this : nil;
else return sidetable_retain(sideTableLocked);
}
...
if (slowpath(carry)) {
// newisa.extra_rc++ overflowed
if (variant != RRVariant::Full) {
ClearExclusive(&isa().bits);
return rootRetain_overflow(tryRetain);
}
// Leave half of the retain counts inline and
// prepare to copy the other half to the side table.
if (!tryRetain && !sideTableLocked) sidetable_lock();
sideTableLocked = true;
transcribeToSideTable = true;
newisa.extra_rc = RC_HALF;
newisa.has_sidetable_rc = true;
}
}

}
}

5._objc_rootRetainCount

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// NSObject.mm
uintptr_t
_objc_rootRetainCount(id obj) {
ASSERT(obj);
return obj->rootRetainCount();
}

// objc-object.h
inline uintptr_t
objc_object::rootRetainCount()
{
if (isTaggedPointer()) return (uintptr_t)this;

sidetable_lock();
isa_t bits = __c11_atomic_load((_Atomic uintptr_t *)&isa().bits, __ATOMIC_RELAXED);
if (bits.nonpointer) {
uintptr_t rc = bits.extra_rc;
if (bits.has_sidetable_rc) {
rc += sidetable_getExtraRC_nolock();
}
sidetable_unlock();
return rc;
}

sidetable_unlock();
return sidetable_retainCount() {
uintptr_t objc_object::sidetable_retainCount()
{
SideTable& table = SideTables()[this];

size_t refcnt_result = 1;

table.lock();
RefcountMap::iterator it = table.refcnts.find(this);
if (it != table.refcnts.end()) {
// this is valid for SIDE_TABLE_RC_PINNED too
refcnt_result += it->second >> SIDE_TABLE_RC_SHIFT;
}
table.unlock();
return refcnt_result;
}
};
}

6._objc_rootAutorelease

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// NSOBject.mm
NEVER_INLINE id
_objc_rootAutorelease(id obj) {
ASSERT(obj);
return obj->rootAutorelease();
}
// objc-object.h
inline id
objc_object::rootAutorelease()
{
if (isTaggedPointer()) return (id)this;
bool nonpointerIsa = false;
#if ISA_HAS_INLINE_RC
nonpointerIsa = isa().nonpointer;

// When we can cheaply determine if the object is deallocating, avoid
// putting it in the pool. Refcounting doesn't work on a deallocating object
// so it's pointless to put it in the pool, and potentially dangerous.
if (nonpointerIsa && isa().isDeallocating()) return (id)this;
#endif

// If the class has custom dealloc initiation, we also want to avoid putting
// deallocating instances in the pool even if it's expensive to check. (UIView
// and UIViewController need this. rdar://97186669)
if (!nonpointerIsa && ISA()->hasCustomDeallocInitiation() && rootIsDeallocating())
return (id)this;

if (prepareOptimizedReturn((id)this, true, ReturnAtPlus1)) return (id)this;
if (slowpath(isClass())) return (id)this;

return rootAutorelease2();
}

// NSOBject.mm
__attribute__((noinline,used))
id
objc_object::rootAutorelease2()
{
ASSERT(!isTaggedPointer());

return AutoreleasePoolPage::autorelease((id)this); // autorelease 后面详细分析
{
static inline id *autoreleaseFast(id obj) {
AutoreleasePoolPage *page = hotPage();
if (page && !page->full()) {
return page->add(obj);
} else if (page) {
return autoreleaseFullPage(obj, page);
} else {
return autoreleaseNoPage(obj);
}
}
}
}

7._objc_rootRelease

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// NSObject.mm
NEVER_INLINE void
_objc_rootRelease(id obj) {
ASSERT(obj)
obj->rootRelease();
}

// objc-object.h
ALWAYS_INLINE bool
objc_object::rootRelease()
{
return rootRelease(true, RRVariant::Fast); // 后面详细分析
}

8._objc_rootDealloc/_objc_rootIsDeallocating

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// NSObject.mm
void
_objc_rootDealloc(id obj) {
ASSERT(obj);
obj->rootDealloc();
}
bool
_objc_rootIsDeallocating(id obj) {
ASSERT(obj);

return obj->rootIsDeallocating();
}

// objc-object.h
inline void
objc_object::rootDealloc()
{
if (isTaggedPointer()) return;

if (fastpath(isa().nonpointer &&
!isa().weakly_referenced &&
!isa().has_assoc &&
#if ISA_HAS_CXX_DTOR_BIT
!isa().has_cxx_dtor &&
#else
!isa().getClass(false)->hasCxxDtor() &&
#endif
!isa().has_sidetable_rc))
{
assert(!sidetable_present());
free(this);
}
else {
object_dispose((id)this);
}
}

inline bool
objc_object::rootIsDeallocating()
{
if (isTaggedPointer()) return false;
if (isa().nonpointer) return isa().isDeallocating();
return sidetable_isDeallocating();
}

9.class_respondsToSelector_inst

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// objc-class.mm
NEVER_INLINE __attribute__((flatten)) BOOL
class_respondsToSelector_inst(id inst, SEL sel, Class cls)
{
// Avoids +initialize because it historically did so.
// We're not returning a callable IMP anyway.
return sel && cls && lookUpImpOrNilTryCache(inst, sel, cls, LOOKUP_RESOLVER);
}

// objc-runtiume-new
IMP lookUpImpOrNilTryCache(id inst, SEL sel, Class cls, int behavior)
{
return _lookUpImpTryCache(inst, sel, cls, behavior | LOOKUP_NIL); {
cache_getImp
lookUpImpOrForward {
checkIsKnownClass(cls);
cls = realizeAndInitializeIfNeeded_locked(inst, cls, behavior & LOOKUP_INITIALIZE);
for (unreasonableClassCount, i: [start, end]) {
if (cls.cache.isConstantOptimizedCache) {
imp = cache_getImp // ① imp缓存
} else { // ② 当前类查询
method_t *m = getMethodNoSuper_nolock(cls, sel); {
method_t *m = search_method_list_inline(*mlists, sel); {
findMethodInSortedMethodList() | findMethodInUnsortedMethodList() {
findMethodInSortedMethodList() {
for(list) -> probe
}
}
}
if (m) return m;
}
if (m) return m;
// ③ 父类查询
if (slowpath((curClass = curClass->getSuperclass()) == nil)) {
// No implementation found, and method resolver didn't help.
// Use forwarding.
imp = forward_imp; // ⑤ 转发
break;
}
// Superclass cache.
imp = cache_getImp(curClass, sel);
}

// No implementation found. Try method resolver once.
if (slowpath(behavior & LOOKUP_RESOLVER)) {
behavior ^= LOOKUP_RESOLVER;
return resolveMethod_locked(inst, sel, cls, behavior); // ④ 动态方法解析
}
}
}
done:
log_and_fill_cache(cls, imp, sel, inst, curClass); // 记录cache
if (slowpath((behavior & LOOKUP_NIL) && imp == forward_imp)) {
return nil; // 如果是转发,返回nil。表示当前类不可相应该方法
}
return imp;


}
}

10.class_conformsToProtocol

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// objc-runtime-new.mm
BOOL class_conformsToProtocol(Class cls, Protocol *proto_gen) {
protocol_t *proto = newprotocol(proto_gen);

if (!cls) return NO;
if (!proto_gen) return NO;

mutex_locker_t lock(runtimeLock);

checkIsKnownClass(cls);

ASSERT(cls->isRealized());

for (const auto& proto_ref : cls->data()->protocols()) { // 遍历protocols列表
protocol_t *p = remapProtocol(proto_ref);
if (p == proto || protocol_conformsToProtocol_nolock(p, proto)) {
return YES;
}
}

return NO;
}

11.class_getMethodImplementation/object_getMethodImplementation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// objc-runtime-new.mm
__attribute__((flatten))
IMP class_getMethodImplementation(Class cls, SEL sel) {
if (!cls || !sel) return nil;

IMP imp = lookUpImpOrNilTryCache(nil, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER); {
_lookUpImpTryCache -> lookUpImpOrForward
}

// Translate forwarding function to C-callable external version
if (!imp) {
return _objc_msgForward;
}

return imp;
}

// objc-class.mm
IMP object_getMethodImplementation(id obj, SEL name) {
Class cls = (obj ? obj->getIsa() : nil);
return class_getMethodImplementation(cls, name);
}

12.class_getName/object_getClassName

1
2
3
4
5
6
7
8
9
10
11
// objc-runtime-new.mm
// If realize=false, the class must already be realized or future.
const char *class_getName(Class cls) {
if (!cls) return "nil";
return cls->demangledName(/* needs lock */true); // 后面详细分析
}

// objc-class.mm
const char *object_getClassName(id obj) {
return class_getName(obj ? obj->getIsa() : nil);
}

13.object_getClass

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// objc-class.mm
Class object_getClass(id obj) {
if (obj) return obj->getIsa();
else return Nil;
}
// objc-object.mm
inline Class
objc_object::getIsa() {
if (fastpath(!isTaggedPointer())) return ISA(/*authenticated*/true);

extern objc_class OBJC_CLASS_$___NSUnrecognizedTaggedPointer;
uintptr_t slot, ptr = (uintptr_t)this;
Class cls;

slot = (ptr >> _OBJC_TAG_SLOT_SHIFT) & _OBJC_TAG_SLOT_MASK;
cls = objc_tag_classes[slot];
if (slowpath(cls == (Class)&OBJC_CLASS_$___NSUnrecognizedTaggedPointer)) {
slot = (ptr >> _OBJC_TAG_EXT_SLOT_SHIFT) & _OBJC_TAG_EXT_SLOT_MASK;
cls = objc_tag_ext_classes[slot];
}
return cls;
}

14.sel_getName

1
2
3
4
5
// objc-sel.mm
const char *sel_getName(SEL sel) {
if (!sel) return "<null selector>";
return (const char *)(const void*)sel;
}

15.sel_registerName

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// objc-sel.mm
SEL sel_registerName(const char *name) {
return __sel_registerName(name, 1, 1); // YES lock, YES copy
}
static SEL __sel_registerName(const char *name, bool shouldLock, bool copy) {
SEL result = 0;

if (shouldLock) lockdebug::assert_unlocked(&selLock);
else lockdebug::assert_locked(&selLock);

if (!name) return (SEL)0;

result = search_builtins(name); {
static SEL search_builtins(const char *name)
{
#if SUPPORT_PREOPT
if (SEL result = (SEL)_dyld_get_objc_selector(name))
return result;
#endif
return nil;
}
}
if (result) return result;

conditional_mutex_locker_t lock(selLock, shouldLock);
auto it = namedSelectors.get().insert(name);
if (it.second) {
// No match. Insert.
*it.first = (const char *)sel_alloc(name, copy);
}
return (SEL)*it.first;
}

3. 结语

通过以上分析,问题的答案不言自明了。

1.什么是 NSObject

NSObject是OC中根类,所有OC对象都是继承自NSObject。从而具有了NSObject的能力,比如消息转发、动态方法解析、与运行时交互的能力等。

2.NSObject 的本质

本质是结构体,运行时加载到内存中仅有一份。
但是它包含两个部分,一个是类对象结构体,一个是元类对象结构体,两种结构体都是objc_class – 继承自 -> objc_object,为实例提供了OOP能力。
通过isa横向连接,串联了实例-类对象-元类对象这条链路。
通过superclass纵向连接,串联了继承关系链。

4. 参考