不可变集合类型
下面的方法适用于如下类型:
NSArray NSDictionary NSIndexSet NSSet NSOrderedSet
|
- (void)bk_each:(void (^)(id obj))block;
|
对数组内的每个元素进行block指定的处理
- (void)bk_apply:(void (^)(id obj))block;
|
这个功能上和bk_each其实是一致的,但是它是异步的,速度上会比bk_each快,特别是在双核处理器上,但是必须注意线程安全,并且它不是按照顺序处理的。
- (id)bk_match:(BOOL (^)(id obj))block;
|
会找到第一个经过block处理后返回YES的元素
- (NSArray *)bk_select:(BOOL (^)(id obj))block;
|
对所有对元素进行block处理,将所有返回YES的元素放到一个数组中返回。
- (NSArray *)bk_reject:(BOOL (^)(id obj))block;
|
这个会剔除掉不匹配的
- (NSArray *)bk_map:(id (^)(id obj))block;
|
对数组进行通用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;
|
查看当前数组和list的对应元素是否对应“相等”。
可变集合类型
下面的方法适用于如下几种可变集合类型:
NSMutableArray NSMutableDictionary NSMutableIndexSet NSMutableOrderedSet NSMutableSet
|
- (void)bk_performSelect:(BOOL (^)(id obj))block;
|
找出满足条件的
- (void)bk_performReject:(BOOL (^)(id obj))block;
|
剔除不满足条件的
- (void)bk_performMap:(id (^)(id obj))block;
|
对各个元素进行map处理
关联对象
- (void)bk_associateValue:(id)value withKey:(const void *)key; + (void)bk_associateValue:(id)value withKey:(const void *)key; - (void)bk_atomicallyAssociateValue:(id)value withKey:(const void *)key; + (void)bk_atomicallyAssociateValue:(id)value withKey:(const void *)key; - (void)bk_associateCopyOfValue:(id)value withKey:(const void *)key; + (void)bk_associateCopyOfValue:(id)value withKey:(const void *)key; - (void)bk_atomicallyAssociateCopyOfValue:(id)value withKey:(const void *)key; + (void)bk_atomicallyAssociateCopyOfValue:(id)value withKey:(const void *)key; - (void)bk_weaklyAssociateValue:(__autoreleasing id)value withKey:(const void *)key; + (void)bk_weaklyAssociateValue:(__autoreleasing id)value withKey:(const void *)key; - (id)bk_associatedValueForKey:(const void *)key; + (id)bk_associatedValueForKey:(const void *)key; - (void)bk_removeAllAssociatedObjects; + (void)bk_removeAllAssociatedObjects;
|
NSInvocation
NSInvocation *invocation = [NSInvocation bk_invocationWithTarget:self block:^(id target) { [target testMethod]; }];
[invocation invoke];
- (void)testMethod { NSLog(@"===>"); }
|
这个用于触发某个target的对应方法,在block中传递进来target对象,直接使用该对象调用方法。
它的最大优点在于能够取消已经对应的block。
- (id)bk_performBlock:(void (^)(id obj))block afterDelay:(NSTimeInterval)delay; + (id)bk_performBlock:(void (^)(void))block afterDelay:(NSTimeInterval)delay; - (id)bk_performBlockInBackground:(void (^)(id obj))block afterDelay:(NSTimeInterval)delay; + (id)bk_performBlockInBackground:(void (^)(void))block afterDelay:(NSTimeInterval)delay; + (id)bk_performBlock:(void (^)(void))block onQueue:(dispatch_queue_t)queue afterDelay:(NSTimeInterval) delay; - (id)bk_performBlock:(void (^)(id obj))block onQueue:(dispatch_queue_t)queue afterDelay:(NSTimeInterval)delay; + (void)bk_cancelBlock:(id)block;
|
KVO
- (NSString *)bk_addObserverForKeyPath:(NSString *)keyPath task:(void (^)(id target))task; - (NSString *)bk_addObserverForKeyPaths:(NSArray *)keyPaths task:(void (^)(id obj, NSString *keyPath))task; - (NSString *)bk_addObserverForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options task:(void (^)(id obj, NSDictionary *change))task; - (NSString *)bk_addObserverForKeyPaths:(NSArray *)keyPaths options:(NSKeyValueObservingOptions)options task:(void (^)(id obj, NSString *keyPath, NSDictionary *change))task; - (void)bk_addObserverForKeyPath:(NSString *)keyPath identifier:(NSString *)token options:(NSKeyValueObservingOptions)options task:(void (^)(id obj, NSDictionary *change))task; - (void)bk_addObserverForKeyPaths:(NSArray *)keyPaths identifier:(NSString *)token options:(NSKeyValueObservingOptions)options task:(void (^)(id obj, NSString *keyPath, NSDictionary *change))task; - (void)bk_removeObserverForKeyPath:(NSString *)keyPath identifier:(NSString *)token; - (void)bk_removeObserversWithIdentifier:(NSString *)token; - (void)bk_removeAllBlockObservers;
|
NSTimer
+ (NSTimer *)bk_scheduledTimerWithTimeInterval:(NSTimeInterval)inTimeInterval block:(void (^)(NSTimer *timer))inBlock repeats:(BOOL)inRepeats; + (NSTimer *)bk_timerWithTimeInterval:(NSTimeInterval)inTimeInterval block:(void (^)(NSTimer *timer))inBlock repeats:(BOOL)inRepeats;
|
UIView
- (void)bk_whenTouches:(NSUInteger)numberOfTouches tapped:(NSUInteger)numberOfTaps handler:(void (^)(void))block;
|
numberOfTouches 多少个手指
numberOfTaps 点击多少次
规定多少个手指,多少点击多少次才会触发该handler Block进行处理。
- (void)bk_whenTapped:(void (^)(void))block; - (void)bk_whenDoubleTapped:(void (^)(void))block;
|
单击双击UIView对象会执行指定的block
- (void)bk_eachSubview:(void (^)(UIView *subview))block;
|
非递归方式遍历当前View的子View
UIGestureRecognizer
UITapGestureRecognizer *singleTap = [UITapGestureRecognizer recognizerWithHandler:^(id sender) { NSLog(@"Single tap."); } delay:0.18]; [self addGestureRecognizer:singleTap];
UITapGestureRecognizer *doubleTap = [UITapGestureRecognizer recognizerWithHandler:^(id sender) { [singleTap cancel]; NSLog(@"Double tap."); }]; doubleTap.numberOfTapsRequired = 2; [self addGestureRecognizer:doubleTap];
|
UIControl
- (void)bk_addEventHandler:(void (^)(id sender))handler forControlEvents:(UIControlEvents)controlEvents; - (void)bk_removeEventHandlersForControlEvents:(UIControlEvents)controlEvents; - (BOOL)bk_hasEventHandlersForControlEvents:(UIControlEvents)controlEvents;
|
部分源码解析:
UIControl
- (void)bk_addEventHandler:(void (^)(id sender))handler forControlEvents:(UIControlEvents)controlEvents{
NSParameterAssert(handler); NSMutableDictionary *events = objc_getAssociatedObject(self, BKControlHandlersKey); if (!events) { events = [NSMutableDictionary dictionary]; objc_setAssociatedObject(self, BKControlHandlersKey, events, OBJC_ASSOCIATION_RETAIN_NONATOMIC); }
NSNumber *key = @(controlEvents); NSMutableSet *handlers = events[key]; if (!handlers) { handlers = [NSMutableSet set]; events[key] = handlers; } BKControlWrapper *target = [[BKControlWrapper alloc] initWithHandler:handler forControlEvents:controlEvents]; [handlers addObject:target]; [self addTarget:target action:@selector(invoke:) forControlEvents:controlEvents]; }
|
UIControl+BlocksKit 中是通过为每个UIControl对象添加一个以UIControlEvents为key,value为BKControlWrapper集合的字典,当我们要为某个UIControlEvents添加一个事件的时候只要找到对应的handlers集合,然后将handler和UIControlEvents封装到BKControlWrapper,然后再调用[self addTarget:target action:@selector(invoke:) forControlEvents:controlEvents];
这样一旦发生controlEvents事件,就会触发BKControlWrapper的invoke方法,在invoke方法中就会执行对应的block。
UIGestureRecognizer
+ (id)bk_recognizerWithHandler:(void (^)(UIGestureRecognizer *sender, UIGestureRecognizerState state, CGPoint location))block delay:(NSTimeInterval)delay { return [[[self class] alloc] bk_initWithHandler:block delay:delay]; }
- (id)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; }
|
初始化的时候会将delay以及block保存到bk_handler以及bk_handlerDelay,并指定当前处理的Action为bk_handleAction。
- (void)bk_handleAction:(UIGestureRecognizer *)recognizer{ void (^handler)(UIGestureRecognizer *sender, UIGestureRecognizerState state, CGPoint location) = recognizer.bk_handler; if (!handler) return; NSTimeInterval delay = self.bk_handlerDelay; CGPoint location = [self locationInView:self.view]; void (^block)(void) = ^{ if (!self.bk_shouldHandleAction) return; handler(self, self.state, location); };
self.bk_shouldHandleAction = YES;
if (!delay) { block(); return; }
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), block); }
|
在对应的手势事件触发的时候会调用bk_handleAction 这时候取出bk_handler,然后根据是否需要延迟执行来执行对应的bk_handler
介绍了UIGestureRecognizer+BlocksKit这里顺带介绍下UIView+BlocksKit,它实际上也是在UIView的基础上添加手势识别器来实现的:
- (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]; }
- (void)bk_whenTapped:(void (^)(void))block{ [self bk_whenTouches:1 tapped:1 handler:block]; }
|
关联对象
这部分没太多新颖的内容,比较有意思的是实现weak方式的关联,它实际上使用了一个中间对象,来做过渡,它持有一个weak类型的属性value来存储实际所赋的值。在获取关联对象时就判断其是否为_BKWeakAssociatedObject类型的对象,如果是就返回该对象value的属性值。
+ (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; }
|
NSObject+BKBlockExecution
- (id)bk_performBlock:(void (^)(id obj))block onQueue:(dispatch_queue_t)queue afterDelay:(NSTimeInterval)delay { NSParameterAssert(block != nil);
__block BOOL cancelled = NO;
void (^wrapper)(BOOL) = ^(BOOL cancel) { if (cancel) { cancelled = YES; return; } if (!cancelled) block(self); }; dispatch_after(BKTimeDelay(delay), queue, ^{ wrapper(NO); });
return [wrapper copy]; }
|
+ (void)bk_cancelBlock:(id)block { NSParameterAssert(block != nil); void (^wrapper)(BOOL) = block; wrapper(YES); }
|
这里使用了一个__block的cacelled标记,标记无效时才执行block。默认情况下就传入NO,使其能正常工作。将要取消时传入YES即可,所以在取消的时候就直接调用了wrapper(YES);
动态代理
BlocksKit的动态代理部分是整个BlocksKit的精华所在,它用于解决什么问题呢?
我们先来看下我们要给一个对象设置代理一般有如下步骤:
1. 创建代理对象 2. 代理对象遵守协议; 3. 代理对象实现协议 4. 将代理对象赋给delegate属性
|
这有个不好的地方就是代码会显得比较散乱,必须要新建一个代理类,并且代理实现方法和设置代理的方法是分开的,这种问题之前我们会采用rac_signalForSelector来将代理实现聚合在设置代理的方法地方。但是这还不算是十分优雅的方式:
在BlocksKit中给出下面的一个例子:
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Hello World!" message:@"This alert's delegate is implemented using blocks. That's so cool!" delegate:nil cancelButtonTitle:@"Meh." otherButtonTitles:@"Woo!", nil];
A2DynamicDelegate *dd = alertView.bk_dynamicDelegate;
[dd implementMethod:@selector(alertViewShouldEnableFirstOtherButton:) withBlock:^(UIAlertView *alertView) { NSLog(@"Message: %@", alertView.message); return YES; }];
[dd implementMethod:@selector(alertView:willDismissWithButtonIndex:) withBlock:^(UIAlertView *alertView, NSInteger buttonIndex) { NSLog(@"You pushed button #%d (%@)", buttonIndex, [alertView buttonTitleAtIndex:buttonIndex]); }];
alertView.delegate = dd;
[alertView show];
|
这个就是BlocksKit动态代理的使用过程:
首先通过bk_dynamicDelegate来获得UIAlertView的动态代理,然后通过implementMethod将代理方法selector与对应的block绑定,最后将动态代理设置给UIAlertView。
整个代码一气呵成。但是背后实际上还是存在代理类的创建,后面会一一向大家介绍整个流程,我们先来看下涉及到的关键类有哪些:
A2BlockInvocation 的主要用于存储和转发block A2DynamicDelegate 用来实现类的代理和数据源 NSObject+A2DynamicDelegate 负责为返回 bk_dynamicDelegate 和 bk_dynamicDataSource 等 A2DynamicDelegate 类型的实例, NSObject+A2BlockDelegate 提供了一系列接口将代理方法映射到 block 上
|
我们接下来顺着上面的例子过一遍代码,看下如何实现动态代理的功能。
在载入UIAlertView+BlocksKit 分类的时候会调用load方法,这里主要做了两件事情,一个是通过bk_registerDynamicDelegate来注册动态代理,另一个是通过bk_linkDelegateMethods将指定的Block与对应的Delegate方法链接起来。
+ (void)load{ @autoreleasepool { [self bk_registerDynamicDelegate]; [self bk_linkDelegateMethods:@{ @"bk_willShowBlock": @"willPresentAlertView:", @"bk_didShowBlock": @"didPresentAlertView:", @"bk_willDismissBlock": @"alertView:willDismissWithButtonIndex:", @"bk_didDismissBlock": @"alertView:didDismissWithButtonIndex:", @"bk_shouldEnableFirstOtherButtonBlock": @"alertViewShouldEnableFirstOtherButton:" }]; } }
|
注册动态代理:
注册动态代理相关代码如下:
+ (void)bk_registerDynamicDelegate { [self bk_registerDynamicDelegateNamed:@"delegate" forProtocol:a2_delegateProtocol(self)]; }
|
Protocol *a2_delegateProtocol(Class cls) { return a2_classProtocol(cls, @"Delegate", @"delegate"); }
static Protocol *a2_classProtocol(Class _cls/*UIAlertView*/, NSString *suffix/*Delegate*/, NSString *description/*delegate*/) { Class cls = _cls; while (cls) { NSString *className = NSStringFromClass(cls); NSString *protocolName = [className stringByAppendingString:suffix]; Protocol *protocol = objc_getProtocol(protocolName.UTF8String); if (protocol) return protocol; cls = class_getSuperclass(cls); } }
|
+ (void)bk_registerDynamicDelegateNamed:(NSString *)delegateName { [self bk_registerDynamicDelegateNamed:delegateName forProtocol:a2_delegateProtocol(self)]; }
|
+ (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); } }
|
static inline A2DynamicDelegate *getDynamicDelegate(NSObject *delegatingObject, Protocol *protocol, const A2BlockDelegateInfo *info, BOOL ensuring) { A2DynamicDelegate *dynamicDelegate = [delegatingObject bk_dynamicDelegateForProtocol:a2_protocolForDelegatingObject(delegatingObject, protocol)]; return dynamicDelegate; }
|
- (id)bk_dynamicDelegateForProtocol:(Protocol *)protocol{ Class class = [A2DynamicDelegate class]; NSString *protocolName = NSStringFromProtocol(protocol); if ([protocolName hasSuffix:@"Delegate"]) { class = a2_dynamicDelegateClass([self class], @"Delegate"); } else if ([protocolName hasSuffix:@"DataSource"]) { class = a2_dynamicDelegateClass([self class], @"DataSource"); } return [self bk_dynamicDelegateWithClass:class forProtocol:protocol]; }
|
static Class a2_dynamicDelegateClass(Class cls, NSString *suffix) { while (cls) { NSString *className = [NSString stringWithFormat:@"A2Dynamic%@%@", NSStringFromClass(cls), suffix]; Class ddClass = NSClassFromString(className); if (ddClass) return ddClass; cls = class_getSuperclass(cls); }
return [A2DynamicDelegate class]; }
|
- (id)bk_dynamicDelegateWithClass:(Class)cls forProtocol:(Protocol *)protocol{
__block A2DynamicDelegate *dynamicDelegate;
dispatch_sync(a2_backgroundQueue(), ^{ dynamicDelegate = objc_getAssociatedObject(self, (__bridge const void *)protocol);
if (!dynamicDelegate) { dynamicDelegate = [[cls alloc] initWithProtocol:protocol]; objc_setAssociatedObject(self, (__bridge const void *)protocol, dynamicDelegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } }); return dynamicDelegate; }
|
最为关键的在于:
+ (void)bk_registerDynamicDelegateNamed:(NSString *)delegateName forProtocol:(Protocol *)protocol;
|
以及
- (id)bk_dynamicDelegateForProtocol:(Protocol *)protocol
|
在bk_registerDynamicDelegateNamed方法中会将通过bk_dynamicDelegateForProtocol方法获取到的代理对象通过关联对象与当前对象产生关联,也就是说将A2DynamicUIAlertViewDelegate对象作为当前的dynamicDelegate属性添加到当前类中,并且原本的delegate存到dynamicDelegate 的 realDelegate对象中,获取delegate的时候,返回就是dynamicDelegate这个管理对象。从而达到替换的目的。也就是说在我们调用delegate的时候实际上是返回A2DynamicUIAlertViewDelegate,这时候系统调用delegate方法的时候会转调A2DynamicUIAlertViewDelegate对应的方法,
我们接下来看下A2DynamicUIAlertViewDelegate中的具体一个代理方法:
- (BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView { BOOL should = YES; id realDelegate = self.realDelegate; if (realDelegate && [realDelegate respondsToSelector:@selector(alertViewShouldEnableFirstOtherButton:)]) should &= [realDelegate alertViewShouldEnableFirstOtherButton:alertView]; BOOL (^block)(UIAlertView *) = [self blockImplementationForMethod:_cmd]; if (block) should &= block(alertView); return should; }
|
在这里调用了blockImplementationForMethod,通过这个方法取出这个代理对应的Block执行。我们看下blockImplementationForMethod方法:
- (id)blockImplementationForMethod:(SEL)selector{ A2BlockInvocation *invocation = nil; if ((invocation = [self.invocationsBySelectors bk_objectForSelector:selector])) return invocation.block; return NULL; }
|
这个方法会通过selector 从 A2BlockInvocation中获取对应的invocation,而block就存在这里,这个接下来会进行介绍。
这里做个简单的总结:
首先在load方法中通过bk_registerDynamicDelegate方法将delegate替换为我们已经实现好的A2DynamicUIAlertViewDelegate,这样在系统事件发生需要调用delegate方法的时候就会将流程转到A2DynamicUIAlertViewDelegate,在这里会通过当前selector从A2BlockInvocation中获取到对应的invocation,block就存在这个invocation中。那么这里就会产生一个问题,selector怎么和invocation产生关联的?我们接下来介绍这部分。
如果我们还有印象的话在load方法中还调用了bk_linkDelegateMethods
+ (void)load{ @autoreleasepool { [self bk_registerDynamicDelegate]; [self bk_linkDelegateMethods:@{ @"bk_willShowBlock": @"willPresentAlertView:", @"bk_didShowBlock": @"didPresentAlertView:", @"bk_willDismissBlock": @"alertView:willDismissWithButtonIndex:", @"bk_didDismissBlock": @"alertView:didDismissWithButtonIndex:", @"bk_shouldEnableFirstOtherButtonBlock": @"alertViewShouldEnableFirstOtherButton:" }]; } }
|
+ (void)bk_linkDelegateMethods:(NSDictionary *)dictionary{ [self bk_linkProtocol:a2_delegateProtocol(self) methods:dictionary]; }
|
bk_linkProtocol是这部分最为关键的方法,会将block与delegate中的selector进行关联。
+ (void)bk_linkProtocol:(Protocol *)protocol methods:(NSDictionary *)dictionary {
[dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *propertyName, NSString *selectorName, BOOL *stop) {
//...... 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); } }]; }
|
我们看下implementMethod
- (void)implementMethod:(SEL)selector withBlock:(id)block { BOOL isClassMethod = self.isClassProxy; struct objc_method_description methodDescription = protocol_getMethodDescription(self.protocol, selector, YES, !isClassMethod); if (!methodDescription.name) methodDescription = protocol_getMethodDescription(self.protocol, selector, NO, !isClassMethod);
A2BlockInvocation *inv = nil; if (methodDescription.name) { NSMethodSignature *protoSig = [NSMethodSignature signatureWithObjCTypes:methodDescription.types]; inv = [[A2BlockInvocation alloc] initWithBlock:block methodSignature:protoSig]; } else { inv = [[A2BlockInvocation alloc] initWithBlock:block]; } [self.invocationsBySelectors bk_setObject:inv forSelector:selector]; }
|
在这里会新建一个A2BlockInvocation并将block 保存到 A2BlockInvocation中,并以selector为key A2BlockInvocation为value 存到self.invocationsBySelectors中。这样上一步就可以通过selector找到A2BlockInvocation进而找到关联的block了,这部分逻辑在blockImplementationForMethod中。
- (id)blockImplementationForMethod:(SEL)selector { A2BlockInvocation *invocation = nil; if ((invocation = [self.invocationsBySelectors bk_objectForSelector:selector])) return invocation.block; return NULL; }
|
但是你们想过没为什么要通过A2BlockInvocation而不是直接将block与selector关联?这其实涉及到下面这些部分,往分类添加的属性,这些属性分类中并没有设置它的getter方法和setter方法。
@property (nonatomic, copy, setter = bk_setCancelBlock:) void (^bk_cancelBlock)(void);
@property (nonatomic, copy, setter = bk_setWillShowBlock:) void (^bk_willShowBlock)(UIAlertView *alertView);
@property (nonatomic, copy, setter = bk_setDidShowBlock:) void (^bk_didShowBlock)(UIAlertView *alertView);
@property (nonatomic, copy, setter = bk_setWillDismissBlock:) void (^bk_willDismissBlock)(UIAlertView *alertView, NSInteger buttonIndex);
@property (nonatomic, copy, setter = bk_setDidDismissBlock:) void (^bk_didDismissBlock)(UIAlertView *alertView, NSInteger buttonIndex);
@property (nonatomic, copy, setter = bk_SetShouldEnableFirstOtherButtonBlock:) BOOL (^bk_shouldEnableFirstOtherButtonBlock)(UIAlertView *alertView) NS_AVAILABLE_IOS(5_0);
|
这样做的目的就是为了通过消息分发机制来找到对应的block。
@implementation UIAlertView (BlocksKit) @dynamic bk_willShowBlock, bk_didShowBlock, bk_willDismissBlock, bk_didDismissBlock, bk_shouldEnableFirstOtherButtonBlock;
|
整个分发过程在A2BlockInvocation类中。
到此为止整个流程已经结束,相关细节可以查看代码中的具体实现。