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

参考链接

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容