ios简单学之3-block和回调

Block使用场景,可以在两个界面的传值,也可以对代码封装作为参数的传递等。用过GCD就知道Block的精妙之处。

Block简介
Block是一种比较特殊的数据类型。
它可以保存一段代码,在合适的时候取出来调用。

举个🌰:无参数无返回值的Block

无参数无返回值的Block
/** * 无参数无返回值的Block */
-(void)func1{ 
/** * void :就是无返回值 
* emptyBlock:就是该block的名字 
* ():这里相当于放参数。由于这里是无参数,所以就什么都不写 */ 
void (^emptyBlock)() = ^() { 
    NSLog(@"无参数,无返回值的Block");
 }; 
    emptyBlock();
}

🌰2:Block结合typedef使用
自己定义一个Block类型,用定义的类型去创建Block,更加简单便捷。
这里举例一个Block回调修改上一下界面的背景颜色。
ViewController1 控制器1,
ViewController2 控制器2控制器1跳转到控制器2,
然后在控制器2触发事件回调修改控制器1的背景颜色为红色。

ViewController2的实现
#import <UIKit/UIKit.h>
@interface ViewController2 : UIViewController
/** * 定义了一个changeColor的Block。这个changeColor必须带一个参数,这个参数的类型必须为id类型的 
* 无返回值 
* @param id */
typedef void(^changeColor)(id);
/** 
* 用上面定义的changeColor声明一个Block,声明的这个Block必须遵守声明的要求。 */
@property (nonatomic, copy) changeColor backgroundColor;
@end
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{ 
  //声明一个颜色 
  UIColor *color = [UIColor redColor]; 
  //用刚刚声明的那个Block去回调修改上一界面的背景
  self.backgroundColor(color);
}

ViewController1的实现

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ 
  ViewController2 *vc =[[ViewController2 alloc]init]; 
  // 回调修改颜色 
  vc.backgroundColor = ^(UIColor *color){ 
    self.view.backgroundColor = color;
  }; 
[self.navigationController pushViewController:vc animated:YES];}

关于block的传值

Block是什么?用一句话来概括就是带有自动变量的匿名函数。
只要用__block定义的变量a, a就是可以在匿名函数中被改变,比如

  __block int multiplier = 7; 
  int multiplier2 = 7; 
  int (^myBlock)(int) = ^(int num)
  { 
      multiplier ++;//这样就可以了 
      multiplier2 = 4;
      return num * multiplier; 
  };

代码输出:
multiplier = 8
multiplier2 = 7
multiplier 被改变了, multiplier2没有被改变;

用__block定义变量multiplier,说明它是可以改变的。

在学习使用块编写的过程中,难点之一是掌握块的语法。本段内容详解介绍块语法,并且会通过示例展示块在代码中的作用。 块类型由返回值类型和参数类型列表构成。使用脱字符(^)可以声明块类型的变量。

20150706201643161.jpg

回调消息:

观察者self, 在收到名为 @"NOTIFICATION_NAME"
的事件是执行 @selector(execute:),最后一个参数是表示会对哪个发送者对象发出的事件作出响应,nil 时表示接受所有发送者的事件。

  [[NSNotificationCenter defaultCenter] postNotificationName:@"NOTIFICATION_NAME"  object:self];

另外,如果需要增加参数,则使用另一个实例:userinfo
首先,我们在需要接收通知的地方注册观察者,比如:

  //获取通知中心单例对象    
  NSNotificationCenter * center = [NSNotificationCenter defaultCenter];    
  //添加当前类对象为一个观察者,name和object设置为nil,表示接收一切通知
  [center addObserver:self selector:@selector(notice:) name:@"123" object:nil];

之后,在我们需要时发送通知消息

//创建一个消息对象    
 NSNotification * notice = [NSNotification notificationWithName:@"123" object:nil userInfo:@{@"1":@"123"}];    
//发送消息      
 [[NSNotificationCenter defaultCenter]postNotification:notice];

我们可以在回调的函数中取到userInfo内容,如下:

-(void)notice:(id)sender{    NSLog(@"%@",sender);}

打印结果如下:

104111_TqQ7_2340880.png

再看一个🌰, 保证队列的串行运行,同时要保证一些操作是同步阻塞的。

- (void)addSession:(id)asession{

    dispatch_block_t addSessionBlock = ^{
        YFVideoRecorderKit* recodeSession = (YFVideoRecorderKit *)(asession);
        [self addKit:recodeSession];
    
        __weak YFSessionManager *wself = self;
        __weak YFVideoRecorderKit *wkit = recodeSession;
    
        //如果开启了录制,监控gpuimage movieWriter的录制结束回调
        recodeSession.movieWriter.completionBlock = ^{
            dispatch_sync(_manager_q, ^{
                [wself removeKit:wkit];  //要用同步或者加锁的方式
              });
        };
        //如果没开录制(初始化和预览状态),监控VideoRecodekit的回调
        recodeSession.finishBlock = ^{
            dispatch_sync(_manager_q, ^{
                [wself removeKit:wkit];  //要用同步或者加锁的方式
            });
        };
       
    };
    
    if (dispatch_get_specific(self.queueManagerKey)) {
        //说明当前的线程队列就是queue
        addSessionBlock();
  
    }else{
        //说明当前的线程队列不是queue, 同步执行
        dispatch_sync(_manager_q, ^{
            addSessionBlock();
        });
    }
}

如何在 block 中修改外部变量
** 考虑到 block 的目的是为了支持并行编程,对于普通的 local 变量,我们就不能在 block 里面随意修改(原因很简单,block 可以被多个线程并行运行,会有问题的),而且如果你在 block 中修改普通的 local 变量,编译器也会报错。那么该如何修改外部变量呢?有两种办法,第一种是可以修改 static 全局变量;第二种是可以修改用新关键字 __block 修饰的变量。请看:**

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
    __block int blockLocal  = 100;
    static int staticLocal  = 100;
    
    void (^aBlock)(void) = ^(void){ 
        NSLog(@" >> Sum: %d\n", global + staticLocal);
        
        global++;
        blockLocal++;
        staticLocal++;
    };
    
    aBlock();

    NSLog(@"After modified, global: %d, block local: %d, static local: %d\n", global, blockLocal, staticLocal);

    [pool drain];

执行之后,值均为:101

参考链接

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容