BlocksKit 源码阅读

文章目录
  1. 1. BlocksKit 能做什么
  2. 2. block 封装集合操作
  3. 3. NSObject 相关封装
    1. 3.1. AssociatedObject
    2. 3.2. BlockExecution
    3. 3.3. BlockObservation
  4. 4. 改造 UIKit
    1. 4.1. 改造 UIGestureRecongizer,UIBarButtonItem 和 UIControl
      1. 4.1.1. UIControlWrapper
    2. 4.2. 改造 UIView
  5. 5. 动态代理
    1. 5.1. 关键的类
    2. 5.2. 核心源码 regist,link
    3. 5.3. 核心流程图
  6. 6. Reference

BlocksKit 能做什么

  1. 为集合类型添加 bk_each: 等函数方法对集合中元素快速遍历
  2. block 对 NSObject 的封装
    1. AssociatedObject:使用 block 封装关联对象
    2. BlockExecution:使用 block 封装块执行
    3. KVO:使用 block 封装 KVO,当 NSObject 销毁自动移除 KVO
  3. UIView 对象添加 bk_whenTapped: 等方法快速添加手势
  4. 动态代理:使用 block 替换 delegate method,不需要实现代理

block 封装集合操作

  1. bk_each:
1
2
3
4
5
6
7
8
9
10
[@[@1,@2,@3] bk_each:^(id obj) {
NSLog(@"%@",obj);
}];

- (void)bk_each:(void (^)(id obj))block {
NSParameterAssert(block != nil);
[self enumerateObjectsUsingBlock:^(id obj,NSUInteger idx,BOOL *stop) {
block(obj);
}];
}
类似的,对于集合函数式方法
1
2
3
4
5
6
7
8
9
10
11
12
13
- (void)bk_each:(void (^)(id obj))block;
- (void)bk_apply:(void (^)(id obj))block;
- (id)bk_match:(BOOL (^)(id obj))block;
- (NSArray *)bk_select:(BOOL (^)(id obj))block;
- (NSArray *)bk_reject:(BOOL (^)(id obj))block;
- (NSArray *)bk_map:(id (^)(id obj))block;
- (id)bk_reduce:(id)initial withBlock:(id (^)(id sum,id obj))block;
- (NSInteger)bk_reduceInteger:(NSInteger)initial withBlock:(NSInteger(^)(NSInteger result,id obj))block;
- (CGFloat)bk_reduceFloat:(CGFloat)inital withBlock:(CGFloat(^)(CGFloat result,id obj))block;
- (BOOL)bk_any:(BOOL (^)(id obj))block;
- (BOOL)bk_none:(BOOL (^)(id obj))block;
- (BOOL)bk_all:(BOOL (^)(id obj))block;
- (BOOL)bk_corresponds:(NSArray *)list withBlock:(BOOL (^)(id obj1,id obj2))block;

NSObject 相关封装

  1. AssociatedObject
  2. BlockExecution
  3. BlockObservation

AssociatedObject

NSObject+BKAssociatedObjects.h

OC 中给class 添加关联属性

associated object policy
1
2
3
4
5
6
7
8
// associated object 的策略中没有 weak
typedef OBJC_ENUM(uintptr_t,objc_AssociationPolicy) {
OBJC_ASSOCIATION_ASSIGN = 0/**< Specifies a weak reference to the associated object. */
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1/**< Specifies a strong reference to the associated object. The association is not made atomically. */
OBJC_ASSOCIATION_COPY_NONATOMIC = 3/**< Specifies that the associated object is copied. The association is not made atomically. */
OBJC_ASSOCIATION_RETAIN = 01401/**< Specifies a strong reference to the associated object. The association is made atomically. */
OBJC_ASSOCIATION_COPY = 01403 /**< Specifies that the associated object is copied. The association is made atomically. */
};
1
2
3
void objc_setAssociatedObject(object, key, value, policy);
id _Nullable objc_getAssociatedObject(id object, key) ;
void objc_removeAssociatedObjects(id _Nonnull object);

BlocksKit 实现

1
2
3
4
5
6
7
8
NSObject *test = [NSObject new];
[test bk_associateValue:@"Draveness" withKey:@"name"];// 添加
NSLog(@"%@",[test bk_associatedValueForKey:@"name"]);// 获取

//内部实现
- (void)bk_associateValue:(id)value withKey:(const void *)key {
objc_setAssociatedObject(self,key,value,OBJC_ASSOCIATION_RETAIN_NONATOMIC);// retain
}

BlocksKit针对每一种 policy都在 NSObject+BKAssociatedObjects.h 中实现了接口。
因为 policy – weak 没有。通过引入一个中间对象来实现『弱属性』

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@interface _BKWeakAssociatedObject : NSObject
@property (nonatomicweak) id value;
@end
@implementation _BKWeakAssociatedObject
@end
// setter
- (void)bk_weaklyAssociateValue:(__autoreleasing id)value withKey:(const void *)key {
_BKWeakAssociatedObject *assoc = objc_getAssociatedObject(self,key);
if (!assoc) {
assoc = [_BKWeakAssociatedObject new];
[self bk_associateValue:assoc withKey:key];
}
assoc.value = value;
}
// getter
- (id)bk_associatedValueForKey:(const void *)key {
id value = objc_getAssociatedObject(self,key);
if (value && [value isKindOfClass:[_BKWeakAssociatedObject class]]) {
return [(_BKWeakAssociatedObject *)value value];
}
return value;
}

obj.weakObj.value

BlockExecution

NSObject+BKBlockExecution.h

在任意对象上执行 block
通过这个类提供的一些接口,可以在任意对象上快速执行线程安全、异步的 block,而且这些 block 也可以在执行之前取消。

1
2
3
4
5
6
- (id <NSObjectNSCopying>)bk_performOnQueue:(dispatch_queue_t)queue afterDelay:(NSTimeInterval)delay usingBlock:(void (^)(id obj))block {
NSParameterAssert(block != nil);
return BKDispatchCancellableBlock(queue,delay,^{
block(self);
});
}

这个方法中最关键的也就是它返回了一个可以取消的 block,而这个 block 就是用静态函数 BKDispatchCancellableBlock 生成的。

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
static id <NSObjectNSCopying> BKDispatchCancellableBlock(dispatch_queue_t queue,NSTimeInterval delay,void(^block)(void)) {
dispatch_time_t time = BKTimeDelay(delay);

#if DISPATCH_CANCELLATION_SUPPORTED
if (BKSupportsDispatchCancellation()) {
dispatch_block_t ret = dispatch_block_create(0,block);
dispatch_after(time,queue,ret);
return ret; //
}
#endif

__block BOOL cancelled = NO;
void (^wrapper)(BOOL) = ^(BOOL cancel) {
if (cancel) {
cancelled = YES;
return;
}
if (!cancelled) block();
};

dispatch_after(time,queue,^{
wrapper(NO);
});

return wrapper; //
}

BKSupportsDispatchCancellation 来判断当前平台和版本是否支持使用 GCD 取消 block,当然一般都是支持的:

  • 函数返回的是 YES,那么在 block 被派发到指定队列之后就会返回这个 dispatch_block_t 类型的 block
  • 函数返回的是 NO,那么就会就会手动包装一个可以取消的 wrapper

上面这部分代码就先创建一个 wrapper block,然后派发到指定队列,派发到指定队列的这个 block 是一定会执行的,但是怎么取消这个 block 呢?

如果当前 block 没有执行,我们在外面调用一次 wrapper(YES) 时,block 内部的 cancelled 变量就会被设置为 YES,所以 block 就不会执行。

  • dispatch_after --- cancelled = NO
  • wrapper(YES) --- cancelled = YES
  • wrapper(NO) --- cancelled = YES block 不会执行

这是实现取消的关键部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
+ (void)bk_cancelBlock:(id <NSObjectNSCopying>)block {
NSParameterAssert(block != nil);

#if DISPATCH_CANCELLATION_SUPPORTED
if (BKSupportsDispatchCancellation()) {
dispatch_block_cancel((dispatch_block_t)block);
return;
}
#endif

void (^wrapper)(BOOL) = (void(^)(BOOL))block;
wrapper(YES);
}
  • GCD 支持取消 block,那么直接调用 dispatch_block_cancel 函数取消 block
  • GCD 不支持取消 block 那么调用一次 wrapper(YES)

BlockObservation

使用 block 封装 的Observation,在添加 observer以后会自动remove。

NSObject+BKBlockObservation.h

BlocksKit 对 KVO 的封装由两部分组成:

  • NSObject+BKBlockObservation 的分类负责提供便利方法
  • 私有类 _BKObserver 具体实现原生的 KVO 功能

主要看点是,BlocksKit 是如何自动remove 掉observer的。
核心技巧:使用method swizzle 替换 dealloc 方法

NSObject+BKBlockObservation 分类中的主要接口:

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
- (void)bk_addObserverForKeyPaths:(NSArray *)keyPaths identifier:(NSString *)identifier options:(NSKeyValueObservingOptions)options context:(BKObserverContext)context task:(id)task {

// 1. 得到全局 swizzle dealloc 的class
Class classToSwizzle = self.class;
NSMutableSet *classes = self.class.bk_observedClassesHash;
@synchronized (classes) {
NSString *className = NSStringFromClass(classToSwizzle);
if (![classes containsObject:className]) {
SEL deallocSelector = sel_registerName("dealloc");

__block void (*originalDealloc)(__unsafe_unretained id, SEL) = NULL;

//1.1. 初始化新的 dealloc 方法
id newDealloc = ^(__unsafe_unretained id objSelf) {
//在方法 dealloc 之前移除所有 observer
[objSelf bk_removeAllBlockObservers];
// 如果子类没有 dealloc 就找父类的 dealloc 方法
if (originalDealloc == NULL) {
struct objc_super superInfo = {
.receiver = objSelf,
.super_class = class_getSuperclass(classToSwizzle)
};

void (*msgSend)(struct objc_super *, SEL) = (__typeof__(msgSend))objc_msgSendSuper;
msgSend(&superInfo, deallocSelector);
} else {
originalDealloc(objSelf, deallocSelector);
}
};
//将 block 转成 imp
IMP newDeallocIMP = imp_implementationWithBlock(newDealloc);
// 1.2. 方法替换
if (!class_addMethod(classToSwizzle, deallocSelector, newDeallocIMP, "v@:")) {
// The class already contains a method implementation.
Method deallocMethod = class_getInstanceMethod(classToSwizzle, deallocSelector);

// We need to store original implementation before setting new implementation
// in case method is called at the time of setting.
originalDealloc = (void(*)(__unsafe_unretained id, SEL))method_getImplementation(deallocMethod);

// We need to store original implementation again, in case it just changed.
originalDealloc = (void(*)(__unsafe_unretained id, SEL))method_setImplementation(deallocMethod, newDeallocIMP);
}
// 1.3替换过 dealloc 的类加到全局集合中
[classes addObject:className];
}
}
//2. 封装observer 上下文
NSMutableDictionary *dict;
_BKObserver *observer = [[_BKObserver alloc] initWithObservee:self keyPaths:keyPaths context:context task:task];
[observer startObservingWithOptions:options];

@synchronized (self) {
dict = [self bk_observerBlocks];// 使用关联对象管理注册 observer

if (dict == nil) {
dict = [NSMutableDictionary dictionary];
[self bk_setObserverBlocks:dict];
}
}

dict[identifier] = observer;
}

// NSObject 类方法,管理swizzled classes
+ (NSMutableSet *)bk_observedClassesHash{
static dispatch_once_t onceToken;
static NSMutableSet *swizzledClasses = nil;
dispatch_once(&onceToken, ^{
swizzledClasses = [[NSMutableSet alloc] init];
});

return swizzledClasses;
}

根据上述代码BlocksKit 主要做了两件事 NSObject+BKBlockObservation.h:

  1. 重写class 的 dealloc 方法
    1. NSObject 分类对象管理更换 dealloc 的 classes
    2. newDealloc 中处理 removeObserver
  2. 管理 _observer(封装KVO 上下文)
    1. 给 class 添加关联对象(一个 dict),用于管理注册的 _observer
    2. _BKObserver 封装 KVO 上下文

改造 UIKit

  • UIGestureRecongizer + UIBarButtonItem + UIControl
  • UIView

改造 UIGestureRecongizer,UIBarButtonItem 和 UIControl

先来看一个 UITapGestureRecognizer 使用的例子

1
2
3
4
UITapGestureRecognizer *singleTap = [UITapGestureRecognizer bk_recognizerWithHandler:^(id sender) {
NSLog(@"Single tap.");
} delay:0.18];
[self addGestureRecognizer:singleTap];

代码中的 bk_recognizerWithHandler:delay: 方法在最后都会调用初始化方法 bk_initWithHandler:delay: 生成一个 UIGestureRecongizer 的实例

1
2
3
4
5
6
7
8
9
- (instancetype)bk_initWithHandler:(void (^)(UIGestureRecognizer *sender,UIGestureRecognizerState state,CGPoint location))block delay:(NSTimeInterval)delay {
self = [self initWithTarget:self action:@selector(bk_handleAction:)];
if (!self) return nil;

self.bk_handler = block;
self.bk_handlerDelay = delay;

return self;
}

它会在这个方法中传入 target 和 selector。 其中 target 就是 self,而 selector 也会在这个分类中实现:

1
2
3
4
5
6
7
8
9
10
11
12
- (void)bk_handleAction:(UIGestureRecognizer *)recognizer {
void (^handler)(UIGestureRecognizer *sender,UIGestureRecognizerState state,CGPoint location) = recognizer.bk_handler;
if (!handler) return;

NSTimeInterval delay = self.bk_handlerDelay;

#1: 封装 block 并控制 block 是否可以执行

self.bk_shouldHandleAction = YES;

[NSObject bk_performAfterDelay:delay usingBlock:block];
}

因为在初始化方法 bk_initWithHandler:delay: 中保存了当前手势的 bk_handler,所以直接调用在 Block Execution 一节中提到过的 bk_performAfterDelay:usingBlock: 方法,将 block 派发到指定的队列中,最终完成对 block 的调用。

封装 block 并控制 block 是否可以执行
这部分代码和前面的部分有些相似,因为这里也用到了一个属性 bk_shouldHandleAction 来控制 block 是否会被执行:

1
2
3
4
5
CGPoint location = [self locationInView:self.view];
void (^block)(void) = ^{
if (!self.bk_shouldHandleAction) return;
handler(selfself.state,location);
};

同样 UIBarButtonItemUIControl 也是用了几乎相同的机制,把 target 设置为 self,让后在分类的方法中调用指定的 block。

UIControlWrapper

稍微有些不同的是 UIControl。因为 UIControl 有多种 UIControlEvents,所以使用另一个类 BKControlWrapper 来封装 handlercontrolEvents

1
2
@property (nonatomic) UIControlEvents controlEvents;
@property (nonatomiccopy) void (^handler)(id sender);

其中 UIControlWrapper 对象以 {controlEvents,wrapper}的形式作为 UIControl 的属性存入字典。

改造 UIView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- (void)bk_whenTouches:(NSUInteger)numberOfTouches tapped:(NSUInteger)numberOfTaps handler:(void (^)(void))block {
if (!block) return;

UITapGestureRecognizer *gesture = [UITapGestureRecognizer bk_recognizerWithHandler:^(UIGestureRecognizer *sender,UIGestureRecognizerState state,CGPoint location) {
if (state == UIGestureRecognizerStateRecognized) block();
}];

gesture.numberOfTouchesRequired = numberOfTouches;
gesture.numberOfTapsRequired = numberOfTaps;

[self.gestureRecognizers enumerateObjectsUsingBlock:^(id obj,NSUInteger idx,BOOL *stop) {
if (![obj isKindOfClass:[UITapGestureRecognizer class]]) return;

UITapGestureRecognizer *tap = obj;
BOOL rightTouches = (tap.numberOfTouchesRequired == numberOfTouches);
BOOL rightTaps = (tap.numberOfTapsRequired == numberOfTaps);
if (rightTouches && rightTaps) {
[gesture requireGestureRecognizerToFail:tap];
}
}];

[self addGestureRecognizer:gesture];
}

UIView 分类只有这一个核心方法,其它的方法都是向这个方法传入不同的参数,这里需要注意的就是。它会遍历所有的 gestureRecognizers,然后把对所有有冲突的手势调用 requireGestureRecognizerToFail: 方法,保证添加的手势能够正常的执行。

动态代理

思考代理模式:

1
2
3
class A -- protocol DelegateA
a.delegate = DelegateA()
// 实现 DelegateA 接口方法

BlocksKit 要改造成

1
2
3
a.delegateBlock0 = ^{ }
a.delegateBlock1 = ^id(int a){ }
...

block:

  1. 不需要设置代理
  2. 不需要实现接口
  3. 让对象自己实现代理方法

BlocksKit 使用了什么方式实现?

这里分析 UIImagePickerController 如何实现的(代码少)

dynamic_delegate

核心构建流程 NSObject+A2BlockDelegate

  1. 注册动态代理:bk_registerDynamicDelegate
  2. 关联block:bk_linkDelegateMethods

硬编码部分:

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
// 1. 自定义delegate class 继承 A2DynamicDelegate,并遵从 UIImagePickerControllerDelegate 方法
#pragma mark Custom delegate
@interface A2DynamicUIImagePickerControllerDelegate : A2DynamicDelegate <UIImagePickerControllerDelegate>
@end

@implementation A2DynamicUIImagePickerControllerDelegate
// 实现 UIImagePickerControllerDelegate 方法,内部调用 block
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
id realDelegate = self.realDelegate;
if (realDelegate && [realDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingMediaWithInfo:)])
[realDelegate imagePickerController:picker didFinishPickingMediaWithInfo:info];

void (^block)(UIImagePickerController *, NSDictionary *) = [self blockImplementationForMethod:_cmd];
if (block) block(picker, info);
}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
id realDelegate = self.realDelegate;
if (realDelegate && [realDelegate respondsToSelector:@selector(imagePickerControllerDidCancel:)])
[realDelegate imagePickerControllerDidCancel:picker];

void (^block)(UIImagePickerController *) = [self blockImplementationForMethod:_cmd];
if (block) block(picker);
}
@end

/*
2. UIKit 分类
2.1 添加回调block
2.2 重写 load 方法,内部添加 { block : delegateMethod } 实现 */
@implementation UIImagePickerController (BlocksKit)
@dynamic bk_didFinishPickingMediaBlock;
@dynamic bk_didCancelBlock;

+ (void)load {
@autoreleasepool {
[self bk_registerDynamicDelegate];
[self bk_linkDelegateMethods:@{
@"bk_didFinishPickingMediaBlock": @"imagePickerController:didFinishPickingMediaWithInfo:",
@"bk_didCancelBlock": @"imagePickerControllerDidCancel:"
}];
}
}
@end

自己以后自定义的组件可以依赖 BlocksKit 通过 block 实现 delegate

  1. 自定义 xxxDynamicDelegate class 继承 A2DynamicDelegate,并遵从 xxxDelegate 方法
  2. Class 分类
    2.1 添加实现 xxxDelegateMethod 的 block
    2.2 重写 load 方法,内部添加 { block : xxxDelegateMethod } 实现

关键的类

  • A2BlockInvocation 的主要作用是存储和转发 block
  • A2DynamicDelegate 用来实现类的代理和数据源,它是 NSProxy 的子类
  • NSObject+A2DynamicDelegate 负责为返回 bk_dynamicDelegatebk_dynamicDataSourceA2DynamicDelegate 类型的实例,为 NSObject 提供主要的接口
  • NSObject+A2BlockDelegate 提供了一系列接口将代理方法映射到 block
  • 其他的 UIKit 的分类提供对应的属性,并在对应的 A2DynamicDelegate 子类中实现代理方法

NSObject+A2BlockDelegate.m

regist
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
+ (void)bk_registerDynamicDelegateNamed:(NSString *)delegateName forProtocol:(Protocol *)protocol {
NSMapTable *propertyMap = [self bk_delegateInfoByProtocol:YES];
A2BlockDelegateInfo *infoAsPtr = (__bridge void *)[propertyMap objectForKey:protocol];
if (infoAsPtr != NULL) { return; }

const char *name = delegateName.UTF8String;
objc_property_t property = class_getProperty(self, name);
SEL setter = setterForProperty(property, name);
SEL a2_setter = prefixedSelector(setter);
SEL getter = getterForProperty(property, name);

A2BlockDelegateInfo info = {
setter, a2_setter, getter
};

[propertyMap setObject:(__bridge id)&info forKey:protocol];
infoAsPtr = (__bridge void *)[propertyMap objectForKey:protocol];

IMP setterImplementation = imp_implementationWithBlock(^(NSObject *delegatingObject, id delegate) {
A2DynamicDelegate *dynamicDelegate = getDynamicDelegate(delegatingObject, protocol, infoAsPtr, YES);
if ([delegate isEqual:dynamicDelegate]) {
delegate = nil;
}
dynamicDelegate.realDelegate = delegate;
});

if (!swizzleWithIMP(self, setter, a2_setter, setterImplementation, "v@:@", YES)) {
bzero(infoAsPtr, sizeof(A2BlockDelegateInfo));
return;
}

if (![self instancesRespondToSelector:getter]) {
IMP getterImplementation = imp_implementationWithBlock(^(NSObject *delegatingObject) {
return [delegatingObject bk_dynamicDelegateForProtocol:a2_protocolForDelegatingObject(delegatingObject, protocol)];
});

addMethodWithIMP(self, getter, NULL, getterImplementation, "@@:", NO);
}
}
link
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
+ (void)bk_linkProtocol:(Protocol *)protocol methods:(NSDictionary *)dictionary{
[dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *propertyName, NSString *selectorName, BOOL *stop) {
const char *name = propertyName.UTF8String;
objc_property_t property = class_getProperty(self, name);
NSCAssert(property, @"Property \"%@\" does not exist on class %s", propertyName, class_getName(self));

char *dynamic = property_copyAttributeValue(property, "D");
NSCAssert2(dynamic, @"Property \"%@\" on class %s must be backed with \"@dynamic\"", propertyName, class_getName(self));
free(dynamic);

char *copy = property_copyAttributeValue(property, "C");
NSCAssert2(copy, @"Property \"%@\" on class %s must be defined with the \"copy\" attribute", propertyName, class_getName(self));
free(copy);

SEL selector = NSSelectorFromString(selectorName);
SEL getter = getterForProperty(property, name);
SEL setter = setterForProperty(property, name);

if (class_respondsToSelector(self, setter) || class_respondsToSelector(self, getter)) { return; }

const A2BlockDelegateInfo *info = [self bk_delegateInfoForProtocol:protocol];

IMP getterImplementation = imp_implementationWithBlock(^(NSObject *delegatingObject) {
A2DynamicDelegate *delegate = getDynamicDelegate(delegatingObject, protocol, info, NO);
return [delegate blockImplementationForMethod:selector];
});

if (!class_addMethod(self, getter, getterImplementation, "@@:")) {
NSCAssert(NO, @"Could not implement getter for \"%@\" property.", propertyName);
}

IMP setterImplementation = imp_implementationWithBlock(^(NSObject *delegatingObject, id block) {
A2DynamicDelegate *delegate = getDynamicDelegate(delegatingObject, protocol, info, YES);
[delegate implementMethod:selector withBlock:block];
});

if (!class_addMethod(self, setter, setterImplementation, "v@:@")) {
NSCAssert(NO, @"Could not implement setter for \"%@\" property.", propertyName);
}
}];
}

核心流程图

dynamic_delegate_flow

time_sequence

使用技术:

  1. block 源码结构解析成 Signature
  2. runtime
    1. 动态添加方法
    2. 关联对象
    3. swizzle
  3. 消息转发

Reference

神奇的 BlocksKit 一
神奇的 BlocksKit 二