iOS

来源:互联网 发布:关于养生之道的软件 编辑:程序博客网 时间:2024/05/22 09:38

Block 是一种苹果开发的基于 C 的调用方式,在 iOS 和 Mac 开发上都有广泛的应用。Block 从某种程度上来说是一种很新的回调方式,苹果在2009年将其引入 Mac OS X 10.6,之后在2010年将其引入到 iOS 4.0。

在iOS开发过程中,回调方式有三种BlockDelegateNSNotification。这三种方式也是各有优缺点,这里只是讲一下Block的几种用法。什么东西都有优点和缺点,就像我除了帅就一无所有,所以的话,我们的Block也是一样的。

  1. Block的优点:方便、简单、快速回调、代码可读性强,尤其处理异步逻辑的时候让你爽的不要不要的。
  2. Block的缺点:
    (1)由多个相关方法。假如每个方法都设置一个block,这样就会很麻烦,这时候就要考虑Delegate。Delegate让多个方法分成一组,只需要设置一次代理就可以完成多次回调。
    (2)循环引用的问题,其实代理用strong修饰(上篇文章讲到的)也同样会有循环引用,但是block更容易产生!因为使用Block的时候稍微不注意可能就会导致对象是放不了,而且一旦出现就比较难检查出来,后果是毁灭性的。但是这个问题是我们完全可以避免的。

循环引用的解决方式就是,外部用__weak typeof(self) weakSelf = self; __weak修饰一下,使外部的self对象能够释放,在Block内部__strong typeof(self) self = weakSelf; __strong修饰一下,让内部能够拿到self对象就OK了。

第一种用法:作为属性传值
应用场景:比如界面之间反向传值

创建一个Person类

#import <Foundation/Foundation.h>/* typedef 定义一个blcok */typedef void (^block) (NSString * name,NSInteger age);@interface Person : NSObject@property (nonatomic,strong)block myBlock; //设置一个blcok属性@end

VC中的代码如下:

//  Created by cuzZLYues on 2017/6/28.//  Copyright © 2017年 cuzZLYues. All rights reserved.//#import "ViewController.h"#import "Person.h"@interface ViewController ()/**    */@property (nonatomic,strong) Person *p;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    Person * p = [[Person alloc]init];    //block 回调    p.myBlock = ^(NSString *name, NSInteger age) {        NSLog(@"我的名字叫%@ 今年%ld岁了",name,age);    };    _p = p;}-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{    //block 传进两个参数    NSString * name = @"LY";    NSInteger age = 18;    _p.myBlock(name, age);}

这样当我惦记屏幕的时候Block就会回调打印:

2017-06-29 14:08:51.070 BlockCircularReferenceDemo[4968:12856691] 我的名字叫LY 今年18岁了

第二种用法:作为方法的参数,主要是外界不能调用,只能在这个方法内部调用,用于回调合传值等。

应用场景:比如网络请求(AFN)

同样是Person类

//  Created by cuzZLYues on 2017/6/28.//  Copyright © 2017年 cuzZLYues. All rights reserved.//#import <Foundation/Foundation.h>@interface Person : NSObject-(void)run:(void(^)())runBlock;@end
-(void)run:(void(^)())runBlock{    NSLog(@"一起跑步吧!");    runBlock();}

VC里面的代码如下:

//  Created by cuzZLYues on 2017/6/28.//  Copyright © 2017年 cuzZLYues. All rights reserved.//#import "ViewController.h"#import "Person.h"@interface ViewController ()/**    */@property (nonatomic,strong) Person *p;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    Person * p = [[Person alloc]init];    [p run:^{        NSLog(@"跑完洗澡澡");    }];}- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}@end

打印结果:

2017-06-29 15:12:52.742 BlockCircularReferenceDemo[5096:12936446] 一起跑步吧!2017-06-29 15:12:52.742 BlockCircularReferenceDemo[5096:12936446] 跑完洗澡澡

把Block作为参数,先执行-(void)run:(void(^)())runBlock;这个方法,等这个方法执行完之后就回调会VC里面的 NSLog(@”跑完洗澡澡”);这句代码。

第三种用法:作为方法的返回值,内部不能调用,只能外界调用。

应用场景:Masonry 的用法 ,链式编程的思想。

还是我们的Person类:

//  Created by cuzZLYues on 2017/6/28.//  Copyright © 2017年 cuzZLYues. All rights reserved.//#import <Foundation/Foundation.h>@interface Person : NSObject- (void(^)())run;@end
//  Created by cuzZLYues on 2017/6/28.//  Copyright © 2017年 cuzZLYues. All rights reserved.//#import "Person.h"@implementation Person- (void(^)())run{    return ^(){        NSLog(@"跑了10圈了");    };}@end

VC代码如下:

//  Created by cuzZLYues on 2017/6/28.//  Copyright © 2017年 cuzZLYues. All rights reserved.//#import "ViewController.h"#import "Person.h"@interface ViewController ()/**    */@property (nonatomic,strong) Person *p;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    Person * p = [[Person alloc]init];    //直接用点语法调用run方法,很几把屌是不是! ()里面可以穿参数的呦!    p.run();}- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}@end

打印:

2017-06-29 15:35:45.464 BlockCircularReferenceDemo[5263:12967469] 跑了10圈了

那么接下来,玩一个变态用法,链式编程用法:

//  Created by cuzZLYues on 2017/6/28.//  Copyright © 2017年 cuzZLYues. All rights reserved.//#import <Foundation/Foundation.h>@interface Person : NSObject//这个run方法的返回值是一个 block ,那么这个block的返回值是 - 方法的调用者 p 对象的类型 Person *- (Person *(^)(int a))run;@end
//  Created by cuzZLYues on 2017/6/28.//  Copyright © 2017年 cuzZLYues. All rights reserved.//#import "Person.h"@implementation Person- (Person * (^)(int a))run{    //这个方法返回一个block    return ^Person *(int a){        NSLog(@"跑了%d圈了",a);       //block的返回值是 self (Person * 类型)        return self;    };}@end
//  Created by cuzZLYues on 2017/6/28.//  Copyright © 2017年 cuzZLYues. All rights reserved.//#import "ViewController.h"#import "Person.h"@interface ViewController ()/**    */@property (nonatomic,strong) Person *p;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    Person * p = [[Person alloc]init];    /*     现在我传一个参数!     p.run 这一步是一个get方法他的返回值是一个带参数的block,也就是这一坨:     return ^Person *(int a){     NSLog(@"跑了%d圈了",a);     //block的返回值是 self (Person * 类型)     return self;     };     p.run(10) 到了这一步,它的返回值就是一个Person对象,所以怎么样,我们能继续点语法一直点点点。。     p.run(10).run(19).run(20);     */    p.run(10).run(19).run(20);}- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}@end

看到注释应该很清楚啦吧,这就是链式编程的思想,以上就是Block的几种玩法啦,希望大家多多支持一下,多多评论,我们互相交流和学习!

最后全部代码在这里:https://github.com/yueShenAAA/BlockUtilize