0%

__weak修饰符

__weak修饰对象时和废弃对象时的调用流程

__weak修饰对象时和废弃对象时的调用流程

__block说明符

原始代码

1
2
3
4
5
6
7
8
9
#import <Foundation/Foundation.h>
int main(int argc, char const *argv[])
{
__block int a = 1;
^{
a ++;
};
return 0;
}

经clang编译后

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
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};


struct __Block_byref_a_0 {
void *__isa;
__Block_byref_a_0 *__forwarding;
int __flags;
int __size;
int a; // 最后一个成员变量相当于源自动变量的成员变量
};

struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__Block_byref_a_0 *a; // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_a_0 *_a, int flags=0) : a(_a->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
__Block_byref_a_0 *a = __cself->a; // bound by ref

(a->__forwarding->a) ++;
}

static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->a, (void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);}

static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);}

static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};

int main(int argc, char const *argv[])
{
// __block 变成了__Block_byref_a_0结构体类型的自动变量,既在栈上生成的__Block_byref_a_0结构体实例,命名规则:__Block_byref_变量名_出现的顺序
__attribute__((__blocks__(byref))) __Block_byref_a_0 a = {
(void*)0,
(__Block_byref_a_0 *)&a,
0,
sizeof(__Block_byref_a_0),
1 // 初始值为1
};

((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344));
return 0;
}

__block变量和对象

1
2
3
4
5
6
7
#import <Foundation/Foundation.h>
int main(int argc, char const *argv[])
{
__block id obj = [[NSObject alloc] init];
// ARC下等同 __block id _strong obj = [[NSObject alloc] init];
return 0;
}
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
/*
当block从栈上复制到堆上时,使用_Block_object_assign函数,持有Block截获的对象
当堆上的Block被废弃时,使用_Block_object_dispose函数,释放Block截获的对象
*/

// __block变量声明部分
struct __Block_byref_obj_0 {
void *__isa;
__Block_byref_obj_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
__strong id obj;
};

int main(int argc, char const *argv[])
{
// __block 变量赋值部分
__attribute__((__blocks__(byref))) __Block_byref_obj_0 obj =
{
(void*)0,
(__Block_byref_obj_0 *)&obj,
33554432,
sizeof(__Block_byref_obj_0),
__Block_byref_id_object_copy_131,
__Block_byref_id_object_dispose_131,
((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"))};

return 0;
}

在堆上生成的Block

创建Block

1
2
3
4
5
6
7
8
#import <Foundation/Foundation.h>
int main()
{
void (^Block)(void) = ^{
printf("Block\n");
};
return 0;
}

经过clang编译后

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

struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};

struct {
struct __block_impl impl;
struct __main_block_desc_0* Desc;

// 构造函数初始化__main_block_impl_0
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock; // _NSConcreteStackBlock用于初始化__block_impl结构体的isa成员
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}

};
// 方法__main_block_func_0传入的是__main_block_impl_0结构体指针
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {

NSLog((NSString *)&__NSConstantStringImpl__var_folders_dp_q1vmhmws4zvd8s8jq5q8f37c0000gn_T_block_5bf957_mi_0);
}

// 描述,
static struct __main_block_desc_0 {
size_t reserved; // 今后版本升级所需的区域
size_t Block_size; // Block的大小
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};


int main(int argc, char const *argv[])
{
// 转换后,变成了__main_block_func_0,其规则是:__Block语法所在的函数名_block_func_block语法在函数中出现的顺序
// void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));

// 去掉转换后
// 将__main_block_impl_0结构体类型的自动变量,既栈上生成的__main_block_impl_0结构体实例指针,赋值给__main_block_impl_0结构体指针类型的block
struct __main_block_impl_0 tmp = __main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA);
struct __main_block_impl_0 *block = &tmp;
||
// 对应以下最初识代码
void (^block)(void) = ^{
printf("Block\n");
};

// ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
// 去掉转换后
(*block -> __block_impl.FuncPtr)(block);

return 0;
}

分配在数据区的全局Block

创建OC的Block原码:

1
2
3
4
5
6
7
8
9
#import <Foundation/Foundation.h>
// 全局Block
void (^blk)(void) = ^{
printf("Global Block\n");
};
int main(int argc, char const *argv[])
{
return 0;
}

用clang命令编译该文件

1
clang -rewrite-objc -fobjc-arc blk.m

得到如下源码(删除辅助代码后)

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
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};

struct __blk_block_impl_0 {
struct __block_impl impl;
struct __blk_block_desc_0* Desc;
__blk_block_impl_0(void *fp, struct __blk_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteGlobalBlock; // 分配在数据区的全局Block
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __blk_block_func_0(struct __blk_block_impl_0 *__cself) {

printf("Global Block\n");
}

static struct __blk_block_desc_0 {
size_t reserved;
size_t Block_size;
} __blk_block_desc_0_DATA = { 0, sizeof(struct __blk_block_impl_0)};
static __blk_block_impl_0 __global_blk_block_impl_0((void *)__blk_block_func_0, &__blk_block_desc_0_DATA);
void (*blk)(void) = ((void (*)())&__global_blk_block_impl_0);

int main(int argc, char const *argv[])
{
return 0;
}

Block自动截获变量

源码

1
2
3
4
5
6
7
8
9
10
11
#import <Foundation/Foundation.h>

int main(int argc, char const *argv[])
{
int a = 1;
const char *fmt = "1";
void (^blk)(void) = ^{
printf("%d %s\n", a, fmt);
};
return 0;
}

编译后:

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
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
// 使用自动变量被当做成员变量追加到__main_block_impl_0结构体中
int a;
const char *fmt;

__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, const char *_fmt, int flags=0) : a(_a), fmt(_fmt) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
int a = __cself->a; // bound by copy
const char *fmt = __cself->fmt; // bound by copy

printf("%d %s\n", a, fmt);
}

static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};

int main(int argc, char const *argv[])
{
int a = 1;
const char *fmt = "1";
void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a, fmt));
return 0;
}

Block修改静态变量:全局变量的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#import <Foundation/Foundation.h>

int global_val = 1; // 全局变量
static int static_global_val = 2; // 静态全局变量

int main(int argc, char const *argv[])
{
static int static_val = 3;// 静态局部变量

void (^blk)(void) = ^{
global_val ++;
static_global_val ++;
static_val ++;
};
return 0;
}

||

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
int global_val = 1;
static int static_global_val = 2;


struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int *static_val; // 使用指针进行访问,这是这是超出作用域最简单的方法
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int *_static_val, int flags=0) : static_val(_static_val) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
int *static_val = __cself->static_val; // bound by copy

// 全局变量和静态全局变量可以直接使用
global_val ++;
static_global_val ++;

// 使用static_val的指针进行访问
(*static_val) ++;
}

static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main(int argc, char const *argv[])
{
static int static_val = 3;

void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, &static_val));
return 0;
}

Block从栈赋值到堆上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#import <Foundation/Foundation.h>

typedef int (^blk_t)(int);

blk_t func(int rate) {
// return ^(int count) {return rate * count;}; // ARC下编译器会自动帮加上copy
return [^(int count) {return rate * count;} copy]; //MRC下需要手动copy
}

NSArray* getBlockArray {
return [NSArray alloc] initWithObjects:
[^{
NSLog(@"blk0");
}; copy],
[^{
NSLog(@"blk1");
}; copy],
}
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
typedef int (*blk_t)(int);


struct __func_block_impl_0 {
struct __block_impl impl;
struct __func_block_desc_0* Desc;
int rate;
__func_block_impl_0(void *fp, struct __func_block_desc_0 *desc, int _rate, int flags=0) : rate(_rate) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static int __func_block_func_0(struct __func_block_impl_0 *__cself, int count) {
int rate = __cself->rate; // bound by copy
return rate * count;}

static struct __func_block_desc_0 {
size_t reserved;
size_t Block_size;
} __func_block_desc_0_DATA = { 0, sizeof(struct __func_block_impl_0)};
blk_t func(int rate) {
return ((int (*)(int))&__func_block_impl_0((void *)__func_block_func_0, &__func_block_desc_0_DATA, rate));
}

Swift闭包(Closure)回调传值

场景:

A页面present到B页面,B页面dismiss到A页面时,把值传递给A页面

1. 在B页面定义一个闭包

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
import UIKit

// 定义一个闭包类型
typealias callBackCompletion = (_ str: String, _ age: Int) -> Void

class NextViewController: UIViewController {
// 定义一个变量,把闭包当变量使用
fileprivate var callBack: callBackCompletion?
private var name: String?
private var age: Int?

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if self.callBack != nil {
self.callBack!(self.name! + "11", self.age! + 22)
self.dismiss(animated: true, completion: nil)
}
}

// MARK: - 回调函数
func setCallBackValue(name: String, age: Int, callBack: @escaping callBackCompletion) {
self.name = name
self.age = age
self.callBack = callBack
}
}

2.在A页面得到值

1
2
3
4
5
6
7
 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let vc = NextViewController()
vc.setCallBackValue(name: "Ghost", age: 20) { (name, age) in
print("\(name, age)")
}
self.present(vc, animated: true, completion: nil)
}

DouBanModel.m

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
#import "DouBanModel.h"
#import <objc/runtime.h>

#pragma mark - 可以写成宏

#define encodeCoderWithRuntime(model)\
unsigned int count = 0;\
Ivar *ivars = class_copyIvarList([model class], &count);\
for (int i = 0; i < count; i ++) {\
Ivar ivar = ivars[i];\
NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];\
id value = [aCoder valueForKey:key];\
[aCoder encodeObject:value forKey:key];\
}\
free(ivars);\

#define initCoderWithRuntime(model)\
self = [super init];\
if (self) {\
unsigned int count = 0;\
Ivar *ivars = class_copyIvarList([model class], &count);\
for (int i = 0; i < count; i ++) {\
Ivar ivar = ivars[i];\
NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];\
id value = [aDecoder decodeObjectForKey:key];\
[self setValue:value forKey:key];\
}\
free(ivars);\
}\
return self;\

@implementation DouBanModel

#pragma mark - 用Runtime实现归档解档
// 存
- (void)encodeWithCoder:(NSCoder *)aCoder {
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([DouBanModel class], &count);
for (int i = 0; i < count; i ++) {
Ivar ivar = ivars[i];
NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];
//归档
id value = [self valueForKey:key];
[aCoder encodeObject:value forKey:key];
}
free(ivars);
}

// 解
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self) {
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([DouBanModel class], &count);
for (int i = 0; i < count; i ++) {
// 取出成员变量
Ivar ivar = ivars[i];
NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];
//归档
id value = [aDecoder decodeObjectForKey:key];
[self setValue:value forKey:key];
}
free(ivars);
}
return self;
}

@end


@implementation MovieInfo

#pragma mark - 模型里面套模型的归档
- (void)encodeWithCoder:(NSCoder *)aCoder {
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([MovieInfo class], &count);
for (int i = 0; i < count; i ++) {
Ivar ivar = ivars[i];
NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];
//归档
id value = [self valueForKey:key];
[aCoder encodeObject:value forKey:key];
}
free(ivars);
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
initCoderWithRuntime(MovieInfo);
}

@end

Demo 地址

https://github.com/GhostClock/Runtime-Demo

NSObject+KVO.h

1
2
3
4
5
6
7
8
9
10
11
#import <Foundation/Foundation.h>

typedef void(^GCObserverBlock)(id observedKey, NSString *keyPath, id oldValue, id newValue);

@interface NSObject (KVO)

- (void)GC_addObserver:(NSObject *)observer forKey:(NSString *)key withBlock:(GCObserverBlock)observerBlock;

- (void)GC_removeObserver:(NSObject *)observer forKey:(NSString *)key;

@end

NSObject+KVO.m

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
//
// NSObject+KVO.m
// Runtime-运行时
//
// Created by GhostClock on 2018/5/17.
// Copyright © 2018年 GhostClock. All rights reserved.
//

#import "NSObject+KVO.h"
#import <objc/runtime.h>
#import <objc/message.h>

@interface GCObservationInfo : NSObject

@property (nonatomic, weak) NSObject *observer;
@property (nonatomic, copy) NSString *keyPath;
@property (nonatomic, copy) GCObserverBlock observerBlock;

@end

@implementation GCObservationInfo

- (instancetype)initWithObserver:(NSObject *)observer keyPath:(NSString *)key block:(GCObserverBlock)observerBlock {
self = [super init];
if (self) {
_observer = observer;
_keyPath = key;
_observerBlock = [observerBlock copy];
}
return self;
}

@end


#pragma mark - ================


static NSString *const KVONotifying = @"GCKVONotifying_";
static NSString *const AssociatedObjectKey = @"AssociatedObjectKey";

@implementation NSObject (KVO)

// 获取方法类型
const char* methodTypeEncoding(Method originalMethod) {
return method_getTypeEncoding(originalMethod);
}

// 观察的属性前面加上set 例如setAge:
NSString * setterForGetter(NSString *key) {
if (key.length <= 0) {
return nil;
}
//把第一个字母变成大写
NSString *firstLetter = [[key substringToIndex:1] uppercaseString];
//其余的全部变成小写
NSString *remainingLetter = [key substringFromIndex:1];
// 拼接成set方法
NSString *setter = [NSString stringWithFormat:@"set%@%@:", firstLetter, remainingLetter];
return setter;
}

// 观察的属性前面要是有 set 前缀和 : 后缀,就将其去掉 setAge: -> age
NSString * getterForSetter(NSString *setter) {
if (setter.length <= 0 || ![setter hasPrefix:@"set"] || ![setter hasSuffix:@":"]) {
return setter;
}

// 删除set开头和:结尾
NSRange range = NSMakeRange(3, setter.length - 4);
NSString *getter = [setter substringWithRange:range];

// 把第一个字母变成小写
NSString *firstLetter = [[getter substringToIndex:1] lowercaseString];
getter = [getter stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:firstLetter];

return getter;
}

#pragma mark - 判断该kvo类有没有这个setter方法
- (BOOL)haveSelector:(SEL)setter {
Class class = object_getClass(self);
unsigned int outCount = 0;
Method *methods = class_copyMethodList(class, &outCount);
for (int i = 0 ; i < outCount; i ++) {
SEL setSelector = method_getName(methods[i]);
if (setSelector == setter) {
free(methods);
return YES;
}
}
free(methods);
return NO;
}

#pragma mark - 重写setter方法
// 新的setter方法在调用原setter方法后,通知每个观察者
static void kvo_setter(id self, SEL _cmd, id newValue) {
NSString *setterName = NSStringFromSelector(_cmd);
NSString *getterName = getterForSetter(setterName);
if (!getterName) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"没有相应的属性" userInfo:nil];
return;
}

id oldValue = [self valueForKey:getterName];

struct objc_super superClass = {
.receiver = self,
.super_class = class_getSuperclass(object_getClass(self))
};

void (*objc_msgSendSuperCasted)(void*, SEL, id) = (void *)objc_msgSendSuper; // 转换objc_msgSendSuper
objc_msgSendSuperCasted(&superClass, _cmd, newValue);

NSMutableArray *observer = objc_getAssociatedObject(self, &AssociatedObjectKey);
for (GCObservationInfo *info in observer) {
if ([info.keyPath isEqualToString:getterName]) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
info.observerBlock(self, getterName, oldValue, newValue);
});
}
}
}

Class kvo_class(id self, SEL _cmd) {
return class_getSuperclass(object_getClass(self));
}

#pragma mark - 动态创建这个kvo类
- (Class)createKVONotifyingClassWithOriginalClassName:(NSString *)originClassName {

NSString *kvoClassName = [KVONotifying stringByAppendingString:originClassName];
// 如果这个kvo类存在,就直接返回
Class kvoClass = NSClassFromString(kvoClassName);
if (kvoClass) {
return kvoClass;
}

// 这个kvo类不存在, 就用runtime创建一个, 父类是该观察者
Class originalClass = object_getClass(self);
kvoClass = objc_allocateClassPair(originalClass, [kvoClassName UTF8String], 0);

// 重写掉系统的class方法
Method originMethod = class_getInstanceMethod(originalClass, @selector(class));
class_addMethod(kvoClass, @selector(class), (IMP)kvo_class, methodTypeEncoding(originMethod));
// 向runtime注册这个类
objc_registerClassPair(kvoClass);

return kvoClass;
}

#pragma mark - 外部方法
- (void)GC_addObserver:(NSObject *)observer forKey:(NSString *)key withBlock:(GCObserverBlock)observerBlock {
// 用setterForGetter获得相应的setter方法,得到型如 setAge: 的选择器
SEL setterSelector = NSSelectorFromString(setterForGetter(key));

Method setterMethood = class_getInstanceMethod([self class], setterSelector);
// 1. 检查对象的类有没有相应的setter方法,如果没有则抛出异常
if (!setterMethood) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"没有相应的属性" userInfo:nil];
return;
}

// 2. 检查对象 isa 指针指向的是否是一个KVO类,如果不是,用runtime新建一个继承原来类的子类,并把 isa 指向这个新建的子类
Class kvoClass = object_getClass(self);
NSString *className = NSStringFromClass(kvoClass);
if (![className hasPrefix:KVONotifying]) {
kvoClass = [self createKVONotifyingClassWithOriginalClassName:className];
// 把isa指向新建的类
object_setClass(self, kvoClass);
}

// 3. 检查对象的KVO类有没有重写过这个类的setter方法,如果没有,添加重写的setter方法
if (![self haveSelector:setterSelector]) {
// 添加setter方法
// class_addMethod(kvoClass, setterSelector, (IMP)kvo_setter, methodTypeEncoding(setterMethood));
class_addMethod([kvoClass class], setterSelector, class_getMethodImplementation(kvoClass, @selector(kvoSetter:)), methodTypeEncoding(setterMethood));
}

// 4.添加这个观察者
GCObservationInfo *observerInfo = [[GCObservationInfo alloc] initWithObserver:observer keyPath:key block:observerBlock];
NSMutableArray *observers = objc_getAssociatedObject(self, &AssociatedObjectKey);
if (!observers) {
observers = [NSMutableArray array];
objc_setAssociatedObject(self, &AssociatedObjectKey, observers, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
[observers addObject:observerInfo];
}

- (void)kvoSetter:(id)newValue {
unsigned int outCount = 0;
Method *methods = class_copyMethodList([self class], &outCount);
for (int i = 0; i < outCount; i ++) {
Method method = methods[i];
NSString *setterName = NSStringFromSelector(method_getName(method));
if ([setterName hasPrefix:@"set"] && [setterName hasSuffix:@":"]) {
NSString *getterName = getterForSetter(setterName);

// 用kvo获取旧值
id oldValue = [self valueForKey:getterName];

struct objc_super superClass;
superClass.receiver = self;
superClass.super_class = class_getSuperclass(object_getClass(self));

// 转换 objc_msgSendSuper
void(* myMsgSendSuper)(void *, SEL, id) = (void *)objc_msgSendSuper;

myMsgSendSuper(&superClass, method_getName(method), newValue);

NSMutableArray *observers = objc_getAssociatedObject(self, &AssociatedObjectKey);
for (GCObservationInfo *info in observers) {
if ([info.keyPath isEqualToString:getterName]) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
info.observerBlock(self, getterName, oldValue, newValue);
});
}
}

break;
}
}
}



- (void)GC_removeObserver:(NSObject *)observer forKey:(NSString *)key {
NSMutableArray *observers = objc_getAssociatedObject(self, &AssociatedObjectKey);
GCObservationInfo *removeInfo = nil;
for (GCObservationInfo *info in observers) {
if ([info.keyPath isEqualToString:key] && info.observer == observer) {
removeInfo = info;
break;
}
}
[observers removeObject:removeInfo];
}

@end

Demo 地址

https://github.com/GhostClock/Runtime-Demo