ios block回调的理解和总结

来源:互联网 发布:知乎2018校园招聘 编辑:程序博客网 时间:2024/06/05 09:12
1. block回调与其他2种回调方式的区别
  1) IOS常用回调方式有3种,如:delegate、NSNotificationCenter和block。

  2) 通知:
    (一对多)在APP中,很多控制器都需要知道一个事件,应该用通知;

  3) delegate:
    “一对一”,对同一个协议,一个对象只能设置一个代理delegate,所以单例对象就不能用代理;block没有协议方法,也不需要delegate代理对象
    代理更注重过程信息的传输:比如发起一个网络请求,可能想要知道此时请求是否已经开始、是否收到了数据、数据是否已经接受完成、数据接收失败

  4) block:
    写法更简练,不需要写protocol、函数等等
    block注重结果的传输:比如对于一个事件,只想知道成功或者失败,并不需要知道进行了多少或者额外的一些信息
    一对一,与代理类似,但是block没有协议方法,也不需要delegate代理对象

    block需要注意防止循环引用:

      ARC下这样防止:
__weak typeof(self) weakSelf = self;
  [yourBlock:^(NSArray *repeatedArray, NSArray *incompleteArray) {
       [weakSelf doSomething];
    }];
    补充: 这三种通信方式都实现了对象之间的解耦合。(解耦合就是两个对象建立了一种通信关系,但是它们没有关联得特别紧。也可以说是他们没有依赖于某一个对象)

2. 什么情况下使用block回调或delegate回调

  1) 公共接口,方法较多也选择用delegate进行解耦(iOS有很多例子比如最常用tableViewDelegate,textViewDelegate)

  2) 异步和简单的回调用block更好 (iOS有很多例子比如常用的网络库AFNetwork,ASIHTTP库,UIAlertView类)

  3) 它们都是为了在具体的实现Delegate或Block中再进行处理,属于策略模式,具体算法在具体算法类中实现。


3. block回调的设计步骤

    1) 先声明: #type void(^MyBlock) (int a,int b)

    2) 定义声明的block

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        [self blockTest:^(int a, int b) {
            int c = a + b;
            NSLog(@"步骤2:%i",c);  //回调函数,这里是先执行步骤1的函数
        }];
    }

    3) 调用block

    - (void)blockTest:(MyBlock )myBlock
    {
        NSLog(@"步骤1");
        myBlock(10,20);
    }


4. block回调例子

  1) 例子1:

    /**
     *  需求:在cell上添加一个Button,点击时跳转到ShowNameViewController控制器
     *  已知:cell上无法使用push方法,这个时候可以在cell上添加一个block回调,然后在MainViewController上使用push方法,从而达到跳转的目的
     */

//MainViewController.h

#import <UIKit/UIKit.h>#import "ShowNameViewController.h"@interface MainViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>{    UITableView    *_tableView;}@end

//MainViewController.m

#import "MainViewController.h"#import "NameListTableViewCell.h"@interface MainViewController ()@end@implementation MainViewController- (id)init{    self = [super init];    if (self) {        self.title = @"玩家列表";    }    return self;}- (void)viewDidLoad {    [super viewDidLoad];        _tableView =[[UITableView alloc]initWithFrame:CGRectMake(0, 0,320.0f,480.0f) style:UITableViewStylePlain];    _tableView.allowsSelection = NO;    _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;  //分割线隐藏    _tableView.dataSource = self;    _tableView.delegate = self;    [self.view addSubview:_tableView];}#pragma mark -- UITableViewDelegate- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{    return 1;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    static NSString *identity = @"identityCell";    NameListTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identity];    if (cell == nil) {        cell = [[NameListTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identity];    }    cell.textLabel.text = @" ";        //实现NameListTableViewCell中的pushToBlock    [cell setPushToBlock:^{        [self pushToVC];        NSLog(@"MainVC");    }];        /*     或者这样也行    cell.pushToBlock = ^{        [self pushToVC];        NSLog(@"MainVC");    };    */        return cell;}- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{    return 200;}- (void)pushToVC{    ShowNameViewController *showVC = [[ShowNameViewController alloc]init];    [self.navigationController pushViewController:showVC animated:YES];}@end

//NameListTableViewCell.h

#import <UIKit/UIKit.h>#import "ShowNameViewController.h"#import "MainViewController.h"typedef void(^PushToBlock)(void);@interface NameListTableViewCell : UITableViewCell@property (nonatomic,copy) PushToBlock pushToBlock;@end


//NameListTableViewCell.m

#import "NameListTableViewCell.h"@implementation NameListTableViewCell- (void)awakeFromNib {}- (void)setSelected:(BOOL)selected animated:(BOOL)animated {    [super setSelected:selected animated:animated];}- (void)layoutSubviews{    [super layoutSubviews];        UIButton *startBtn = [UIButton buttonWithType:UIButtonTypeCustom];    startBtn.frame = CGRectMake(60, 100, 200, 30);    [startBtn setBackgroundImage:[UIImage imageNamed:@"singBtn_image"] forState:UIControlStateNormal];    [startBtn setTitle:@"查找" forState:UIControlStateNormal];    [startBtn addTarget:self action:@selector(startAction) forControlEvents:UIControlEventTouchUpInside];    startBtn.layer.masksToBounds = YES;    startBtn.layer.cornerRadius = 2.5;    [self.contentView addSubview:startBtn];}//鼠标点击后执行回调- (void)startAction{    if (self.pushToBlock) {        self.pushToBlock();        NSLog(@"回调函数");    }}@end

//ShowNameViewController.h

#import <UIKit/UIKit.h>@interface ShowNameViewController : UIViewController@end

//ShowNameViewController.m

@implementation ShowNameViewController- (void)viewDidLoad {    [super viewDidLoad];    self.view.backgroundColor = [UIColor greenColor];}- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}@end

---------------------------------------------------------------------------------------------------------

  2) 例子2:

/**

 *  需求:点击按钮后,在UIView中增加一个新的view视图和view对应的颜色(一个矩形)

 *  在声明block的时候,参数中加入View颜色

 */

//MainViewController.h

#import <UIKit/UIKit.h>typedef void(^ViewBlock)(UIColor *color,CGRect rect);@interface MainViewController : UIViewController/** *  将block作为参数传给该函数,从而用来改变视图的size和color * *  @param viewBlock block名 */+ (void)changeViewSizeAndColor:(ViewBlock)viewBlock;@end

//MainViewController.m

#import "MainViewController.h"@interface MainViewController ()@end@implementation MainViewController- (id)init{    self = [super init];    if (self) {        self.title = @"玩家列表";    }    return self;}- (void)viewDidLoad {    [super viewDidLoad];        UIButton *startBtn = [UIButton buttonWithType:UIButtonTypeCustom];    startBtn.frame = CGRectMake(60, 100, 200, 30);    [startBtn setBackgroundImage:[UIImage imageNamed:@"singBtn_image"] forState:UIControlStateNormal];    [startBtn setTitle:@"查找" forState:UIControlStateNormal];    [startBtn addTarget:self action:@selector(startAction) forControlEvents:UIControlEventTouchUpInside];    startBtn.layer.masksToBounds = YES;    startBtn.layer.cornerRadius = 2.5;    [self.view addSubview:startBtn];}- (void)startAction{    [MainViewController changeViewSizeAndColor:^(UIColor *color, CGRect rect) {        NSLog(@"步骤2");        self.view.backgroundColor = [UIColor orangeColor];        UIView *view = [[UIView alloc]init];        view.frame = rect;        view.backgroundColor = color;        [self.view addSubview:view];    }];}+ (void)changeViewSizeAndColor:(ViewBlock)viewBlock{    NSLog(@"步骤1");    UIColor *tempColor = [UIColor redColor];    CGRect  tempRect = CGRectMake(130, 180, 80, 80);    viewBlock(tempColor,tempRect);}@end


例子3:

最简单的例子

    void (^myBlock)(int a,int b);        myBlock = ^(int a,int b){        NSLog(@"result:%d",a + b); //然后回调 步骤2        NSLog(@"start2");    };        NSLog(@"start1");    myBlock(10,20);  //先执行这里 步骤1        //最后输出为:    /*     start1     result:30     start2     */


//例子3:

让某个方法延时执行

    double delayInSeconds = 10;    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);    dispatch_after(popTime, dispatch_get_main_queue(), ^{        [self setImageURL];    });





0 0
原创粉丝点击