WCBlock 使你的代码更加简单:
https://github.com/manakiaHk/WCBlock
一个轻量级的UIKit Extension Block库
它为NotificationCenter、KVO、Target-action、GestureRecognizer、UIView、UIButton、UITextField等的事件响应提供了很友好的block回调支持。提高代码的聚合度,使编码更加轻松,提高开发效率。
相信大家对iOS开发都已经非常娴熟,然而你或许还是在对自己无时无刻都在写相同的代码而感到枯燥乏味,你或许考虑过自己实现一套方法把自己从中解放出来。当然,你或许对你每天所面临的枯燥已经抱着无所谓的心态,我想你大概已经习惯如此。但是不管怎么样,解放是人类的天性,这点我们得承认。
我们一起来回顾一下你上周写过的一些代码:
比如:
1. 一个UIView 、UIImageView 对象的点击,我猜你大概是这样写的:
- (void)aMethod {
UIView *view = [[UIView alloc]init];
UITapGestureRecognizer *viewTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(viewTaped:)];
[view addGestureRecognizer:viewTap];
UIImageView *imageView = [[UIImageView alloc]init];
UITapGestureRecognizer *imgTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(viewTaped:)];
imageView.userInteractionEnabled = YES;
[imageView addGestureRecognizer:imgTap];
}
- (void)viewTaped:(UIGestureRecognizer*)ges {
// your code...
}
2. 一个按钮的点击,你大概这样写的:
- (void)aMethod {
UIButton *button0 = [[UIButton alloc]init];
[button0 addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)buttonClicked:(id)sender {
// your code...
}
3. 一个文本输入框的监听,你大概是这样写的:
///你首先要遵守协议
@interface YourClass ()<UITextFieldDelegate>
@end
-----------
- (void)aMethod {
UITextField *textf = [[UITextField alloc]init];
textf.delegate = self;/// 你要设置代理
}
///你最后还要实现代理的协议
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
// your code...
return YES;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField {
// your code...
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
// your code...
return YES;
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
// your code...
return YES;
}
或者 你这样写的:
- (void)aMethod {
UITextField *textf = [[UITextField alloc]init];
[textf addTarget:self action:@selector(textFieldChanged:) forControlEvents:UIControlEventEditingChanged];
}
- (void)textFieldChanged:(UITextField*)textField{
// your code...
}
4. 再来看看你的KVO
- (void)aMethod {
[_anObject addObserver:self forKeyPath:@"keyPath0" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
[_anObject addObserver:self forKeyPath:@"keyPath1" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
[_anObject addObserver:self forKeyPath:@"keyPath2" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey> *)change context:(void *)context {
// your code...
}
- (void)dealloc {
[_anObject removeObserver:self forKeyPath:@"keyPath0"];
[_anObject removeObserver:self forKeyPath:@"keyPath1"];
[_anObject removeObserver:self forKeyPath:@"keyPath2"];
}
5. 你一般大概都这样使用通知中心的:
- (void)aMethod {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(noteReceived:) name:kNoteName object:nil];
/*
_observer = [[NSNotificationCenter defaultCenter] addObserverForName:kNoteName object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
// your code
}];
*/
}
- (void)noteReceived:(NSNotification*)note {
// your code ...
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:kNoteName object:nil];
/*
if (_observer) {
[[NSNotificationCenter defaultCenter] removeObserver:_observer name:kNoteName object:nil];
}
*/
}
6. 再比如一个简单的弹框提示:
@interface YourClass ()<UIAlertViewDelegate>
@end
---------
- (void)aMethod {
UIAlertView *alert = [[UIAlertView alloc]init];
alert.delegate = self;
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
// your code
}
5. 再比如有这样一个场景:在2个以上的方法中同时监听一个按钮的点击或者一个文本框的输入或者一个键值观察,你可能会停下来好好想想怎么去实现。
还有很多以上类似的应用场景 ,我相信你写这些代码的时候都恨不得编译器能清楚的知道你的用意并且为你自动填充这些重复的代码。节约下来的时间足够你喝一杯的咖啡来养养神。
接下来看看WCBlock 能为你做些什么
1 .控件的交互事件回调
[view wc_bindViewTapBlockNext:^(UIView *view, WCViewTap *tap) {
// your code...
}];
imageView.userInteractionEnabled = YES;//对于imageView 的userInteractionEnabled 属性保留apple api的做法,你需要主动设置为YES
[imageView wc_bindViewTapBlockNext:^(UIView *view, WCViewTap *tap) {
// your code...
}];
///你可以通过返回值设置属性以及代理 这点和Apple的api完全一样 ,比如:
WCViewTap *tap = [view wc_bindViewTapBlockNext:^(UIView *view, WCViewTap *tap) {
// your code...
}];
tap.numberOfTapsRequired = 2;
tap.delegate = self;
///你还可以为view绑定其他的手势block回调。e.g:
[view wc_bindViewPanBlockNext:^(UIView *view, WCViewPan *pan) {
// your code...
}];
[view wc_bindViewLongPressBlockNext:^(UIView *view, WCViewLongPress *longPress) {
// your code...
}];
[view wc_bindViewRotationBlockNext:^(UIView *view, WCViewRotation *rotation) {
// NSLog(@"%0.2f",rotation.rotation);//旋转角度
// NSLog(@"%0.2f",rotation.velocity);//旋转速度
}];
2. 手势回调
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]init];
[tapGes wc_bindGestureBlockNext:^(UIGestureRecognizer *sender) {
//...
}];
UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc]init];
[swipeGesture wc_bindGestureBlockNext:^(UIGestureRecognizer *sender) {
//...
}];
UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc]init];
[rotationGesture wc_bindGestureBlockNext:^(UIGestureRecognizer *sender) {
//...
}];
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc]init];
[panGesture wc_bindGestureBlockNext:^(UIGestureRecognizer *sender) {
//...
}];
3. button、segmentedControl、 slider and so on. e.g:
UIButton *button = [[UIButton alloc]initWithFrame:btnFrame];
[button wc_bindForControlEvents:UIControlEventTouchUpInside blockNext:^(id sender) {
//button clicked...
}];
UISegmentedControl *segment = [[UISegmentedControl alloc]initWithItems:@[@"title0",@"title1",@"title2"]];
[segment wc_bindSegmentControlValueChangedBlockNext:^(NSInteger selectedIndex) {
// NSLog(@"segment selected index %ld",selectedIndex);
}];
//tip: 和以往一样,当wcblock 捕获了外部变量,可能将导致循环引用 ,你需要用 __weak 避免这样事情发生
UISlider *slider = [[UISlider alloc]initWithFrame:sliderFrame];
__weak typeof(self) weakSelf = self;
[slider wc_bindSliderValueChangedBlockNext:^(CGFloat value) {
__strong typeof(weakSelf) self = weakSelf;
[self sendAMesseage];
}];
UIAlertView *alerView = [[UIAlertView alloc]initWithTitle:@"title" message:@"message" delegate:nil cancelButtonTitle:@"cancle" otherButtonTitles:@"ok", nil];
[alerView wc_bindAlertButtonClickedBlockNext:^(NSInteger index) {
// NSLog(@"clicked index: %ld",index);
}];
[alerView show];
4. 文本输入框 textField
UITextField *textfiled = [[UITextField alloc]initWithFrame:textFieldframe];
[textfiled wc_bindTextFieldEditingChangedBlockNext:^(UITextField *textField, NSString *value) {
//NSLog(@"textfiled text:%@",value);
}];
[textfiled wc_bindTextFieldShouldChangeCharactersHandlerBlock:^BOOL(UITextField *textField, NSRange shouldChangeCharactersInRange, NSString *replacementString) {
return YES;
}];
[textfiled wc_bindTextFieldEditingDidBeginBlockNext:^(UITextField *textField) {
//textfiled did begin editing...
}];
[textfiled wc_bindTextFieldEditingDidEndBlockNext:^(UITextField *textField) {
//textfiled did end editing...
}];
5. 通知, WCBlock 将自动为你管理移除通知中心的observer对象
[WCNotificationCenter wc_addObserverForName:kNoteName object:nil contextObj:self blockNext:^(NSNotification * _Nullable note) {
//..
}];
//异步通知用
[WCNotificationCenter wc_addObserverForName:kNoteName object:nil contextObj:self queue: [NSOperationQueue mainQueue] blockNext:^(NSNotification * _Nullable note) {
//..
}];
6. KVO
[_anObject wc_addObserverForKeyPath:@"keyPath0" valueBlockNext:^(NSString *keypath, id ofObj, id oldValue, id newValue) {
//..
}];
[_anObject wc_addObserverForKeyPaths:@[@"keyPath1",@"keyPath2"] valueBlockNext:^(NSString *keypath, id ofObj, id oldValue, id newValue) {
if ([keypath isEqualToString:@"keyPath1"]) {
//..
}else if([keypath isEqualToString:@"keyPath2"]){
//..
}else;
}];
[_anObject wc_addObserverForKeyPath:@"keyPath3" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld changeBlockNext:^(NSString *keypath, id ofObj, NSDictionary<NSKeyValueChangeKey> *change) {
//..
}];
和Apple api 一样 对于KVO 你需要自己移除键值观察, 像这样:
- (void)dealloc {
[_anObject wc_removeObserverForKeyPath:@"keyPath0"];
[_anObject wc_removeObserverForKeyPath:@"keyPath1"];
[_anObject wc_removeObserverForKeyPaths:@[@"keyPath2",@"keyPath3"]];
}
你可以为每个对象绑定多个同样类型的block ,每个block都会调用 ,因为不排除你会在多个地方同时使用,所以你要知道WCBlock是可以做到这点的。 但是记住 handerBlock 除外,它只能绑定一个,因为你并不希望多个hander同时操作同一个对象,所以对于同一个对象 绑定多个同样类型的handler block ,这时候只有最后一个有效。e.g: 像下面的每个block都将调用
[view wc_bindViewTapBlockNext:^(UIView *view, WCViewTap *tap) {
NSLog(@"0--view taped");
}];
[view wc_bindViewTapBlockNext:^(UIView *view, WCViewTap *tap) {
NSLog(@"1--view taped");
}];
[view wc_bindViewTapBlockNext:^(UIView *view, WCViewTap *tap) {
NSLog(@"2--view taped");
}];
[textfiled wc_bindTextFieldEditingChangedBlockNext:^(UITextField *textField, NSString *value) {
NSLog(@"0--textfiled text:%@",value);
}];
[textfiled wc_bindTextFieldEditingChangedBlockNext:^(UITextField *textField, NSString *value) {
NSLog(@"1--textfiled text:%@",value);
}];
[textfiled wc_bindTextFieldEditingChangedBlockNext:^(UITextField *textField, NSString *value) {
NSLog(@"2--textfiled text:%@",value);
}];
像下面的 block 只有最后一个有效(请注意,它们是 HandlerBlock)
[textfiled wc_bindTextFieldShouldChangeCharactersHandlerBlock:^BOOL(UITextField *textField, NSRange shouldChangeCharactersInRange, NSString *replacementString) {
if ([replacementString containsString:@"a"]) {
return NO;
}
return YES;
}];
[textfiled wc_bindTextFieldShouldChangeCharactersHandlerBlock:^BOOL(UITextField *textField, NSRange shouldChangeCharactersInRange, NSString *replacementString) {
if ([replacementString containsString:@"b"]) {
return NO;
}
return YES;
}];
[textfiled wc_bindTextFieldShouldChangeCharactersHandlerBlock:^BOOL(UITextField *textField, NSRange shouldChangeCharactersInRange, NSString *replacementString) {
if ([replacementString containsString:@"c"]) {
return NO;
}
return YES;
}];