下面介绍一点常用方法,是为了让你看到这个方法,会联想到其他方法的如何让使用,只是为了起到一个抛砖引玉的作用。
UIKit相关的Block
1、UIButton
[button bk_addEventHandler:^(id sender) {
// do something
} forControlEvents:UIControlEventTouchUpInside];
2、UITextField
[testField setBk_shouldReturnBlock:^BOOL(UITextField *field) {
// do something like
[self.view endEditing:YES];
return YES;
}];
3、UIGestureRecognizer
[UITapGestureRecognizer bk_recognizerWithHandler:^(UIGestureRecognizer * _Nonnull sender, UIGestureRecognizerState state, CGPoint location) {
} delay:0.2];
4、UIWebView
[webView bk_setDidFinishWithErrorBlock:^(UIWebView *webView, NSError *error) {
// do something with error
}];
5、UIBarButtonItem
[item bk_initWithTitle:@"title" style:UIBarButtonItemStylePlain handler:^(id _Nonnull sender) {
}];
Foundation相关的Block
1、部分不可变容器的BlocksKit声明
//串行遍历容器中所有元素
- (void)bk_each:(void (^)(id obj))block;
//并发遍历容器中所有元素(不要求容器中元素顺次遍历的时候可以使用此种遍历方式来提高遍历速度)
- (void)bk_apply:(void (^)(id obj))block;
//返回第一个符合block条件(让block返回YES)的对象
- (id)bk_match:(BOOL (^)(id obj))block;
//返回所有符合block条件(让block返回YES)的对象
- (NSArray *)bk_select:(BOOL (^)(id obj))block;
//返回所有!!!不符合block条件(让block返回YES)的对象
- (NSArray *)bk_reject:(BOOL (^)(id obj))block;
//返回对象的block映射数组
- (NSArray *)bk_map:(id (^)(id obj))block;
//查看容器是否有符合block条件的对象
//判断是否容器中至少有一个元素符合block条件
- (BOOL)bk_any:(BOOL (^)(id obj))block;
//判断是否容器中所有元素都!!!不符合block条件
- (BOOL)bk_none:(BOOL (^)(id obj))block;
//判断是否容器中所有元素都符合block条件
- (BOOL)bk_all:(BOOL (^)(id obj))block;
使用:
NSString* str = [arr bk_match:^BOOL(id _Nonnull obj) {
return ((NSString *)obj).length == 1;
}];
NSArray* arr_01 = [arr bk_select:^BOOL(id _Nonnull obj) {
return ((NSString *)obj).length == 1;
}];
NSArray* arr_02 = [arr bk_reject:^BOOL(id _Nonnull obj) {
return ((NSString *)obj).length == 1;
}];
NSLog(@"str = %@",str);
NSLog(@"arr_01 = %@",arr_01);
NSLog(@"arr_02 = %@",arr_02);
2、部分可变容器的BlocksKit声明
/** Filters a mutable array to the objects matching the block.
@param block A single-argument, BOOL-returning code block.
@see <NSArray(BlocksKit)>bk_reject:
*/
//删除容器中!!!不符合block条件的对象,即只保留符合block条件的对象
- (void)bk_performSelect:(BOOL (^)(id obj))block;
//删除容器中符合block条件的对象
- (void)bk_performReject:(BOOL (^)(id obj))block;
//容器中的对象变换为自己的block映射对象
- (void)bk_performMap:(id (^)(id obj))block;
3、关联对象相关的BlocksKit
关联对象的作用如下:
在类的定义之外为类增加额外的存储空间。使用关联,我们可以不用修改类的定义而为其对象增加存储空间。这在我们无法访问到类的源码的时候或者是考虑到二进制兼容性的时候是非常有用。关联是基于关键字的,因此,我们可以为任何对象增加任意多的关联,每个都使用不同的关键字即可。关联是可以保证被关联的对象在关联对象的整个生命周期都是可用的(ARC下也不会导致资源不可回收)。
关联对象的例子,在我们的实际项目中的常见用法一般有category中用关联对象定义property,或者使用关联对象绑定一个block。
关联对象相关的BlocksKit是对objc_setAssociatedObject、objc_getAssociatedObject、objc_removeAssociatedObjects这几个原生关联对象函数的封装。主要是封装其其内存管理语义。
//@interface NSObject (BKAssociatedObjects)
//以OBJC_ASSOCIATION_RETAIN_NONATOMIC方式绑定关联对象
- (void)bk_associateValue:(id)value withKey:(const void *)key;
//以OBJC_ASSOCIATION_COPY_NONATOMIC方式绑定关联对象
- (void)bk_associateCopyOfValue:(id)value withKey:(const void *)key;
//以OBJC_ASSOCIATION_RETAIN方式绑定关联对象
- (void)bk_atomicallyAssociateValue:(id)value withKey:(const void *)key;
//以OBJC_ASSOCIATION_COPY方式绑定关联对象
- (void)bk_atomicallyAssociateCopyOfValue:(id)value withKey:(const void *)key;
//弱绑定
- (void)bk_weaklyAssociateValue:(__autoreleasing id)value withKey:(const void *)key;
//删除所有绑定的关联对象
- (void)bk_removeAllAssociatedObjects;
4、逻辑执行相关的BlocksKit
所谓逻辑执行,就是Block块执行。逻辑执行相关的BlocksKit是对dispatch_after
函数的封装
//@interface NSObject (BKBlockExecution)
//主线程执行block方法,延迟时间可选
- (BKCancellationToken)bk_performAfterDelay:(NSTimeInterval)delay usingBlock:(void (^)(id obj))block;
//后台线程执行block方法,延迟时间可选
- (BKCancellationToken)bk_performInBackgroundAfterDelay:(NSTimeInterval)delay usingBlock:(void (^)(id obj))block;
//所有执行block相关的方法都是此方法的简化版,该函数在指定的block队列上以指定的时间延迟执行block
- (BKCancellationToken)bk_performOnQueue:(dispatch_queue_t)queue afterDelay:(NSTimeInterval)delay usingBlock:(void (^)(id obj))block;
//取消block,非常牛逼!!!一般来说一个block加到block queue上是没法取消的,此方法实现了block的取消操作(必须是用BlocksKit投放的block)
+ (void)bk_cancelBlock:(id <NSObject, NSCopying>)block;
5、KVO相关BlocksKit
KVO主要涉及两类对象,即“被观察对象“和“观察者“。
与“被观察对象”相关的函数主要有如下两个:
//添加观察者
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
//删除观察者
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(void *)context;
//与“观察者“相关的函数如下:
//观察到对象发生变化后的回调函数(观察回调)
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
通常的KVO做法是先对“被观察对象”添加“观察者”,同时在“观察者”中实现观察回调。这样每当“被观察对象”的指定property改变时,“观察者”就会调用观察回调。
KVO相关BlocksKit弱化了“观察者”这种对象,使得每当“被观察对象”的指定property改变时,就会调起一个block。具体实现方式是定义一个_BKObserver类,让该类实现观察回调、对被观察对象添加观察者和删除观察者。
使用BlocksKit:
- (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;
6、定时器相关BlocksKit
NSTimer有个比较恶心的特性,它会持有它的target。比如在一个controller中使用了timer,并且timer的target设置为该controller本身,那么想在controller的dealloc中fire掉timer是做不到的,必须要在其他的地方fire。这会让编码很难受。具体参考《Effective Objective C》的最后一条。 BlocksKit解除这种恶心,其方式是把timer的target设置为timer 的class对象。把要执行的block保存在timer的userInfo中执行。因为timer 的class对象一直存在,所以是否被持有其实无所谓。