block是代码块,其本质和变量类似。不同的是代码块存储的数据是一个函数体。使用Block,就可以像其他标准函数一样,传入参数,并得到返回值。
可以把Block当做Objective-C的匿名函数,Block允许开发者在两个对象之间将任意的语句当做数据进行传递,block的实现具有封闭性(closure),而又能够很容易获取上下文的相关状态信息。
Block使用场景,可以在两个界面的传值,也可以对代码封装作为参数的传递等。
ARC情况下
1.如果用copy修饰Block,该Block就会存储在堆空间。则会对Block的内部对象进行强引用,导致循环引用。内存无法释放。
解决方法:
新建一个指针(__weak typeof(Target) weakTarget = Target )指向Block代码块里的对象,然后用weakTarget进行操作。就可以解决循环引用问题。
2.如果用weak修饰Block,该Block就会存放在栈空间。不会出现循环引用问题。
MRC情况下
用copy修饰后,如果要在Block内部使用对象,则需要进行(__block typeof(Target) blockTarget = Target )处理。在Block里面用blockTarget进行操作。
默认情况下,Block内部不能修改外面的局部变量。
Block内部可以修改使用__block修饰的局部变量。
1、无参数无返回值的Block
/** * void :就是无返回值 * emptyBlock:就是该block的名字 * ():这里相当于放参数。由于这里是无参数,所以就什么都不写 */ void (^emptyBlock)() = ^(){ NSLog(@"无参数,无返回值的Block"); }; emptyBlock();
2、有参数无返回值的Block
/** * 调用这个block进行两个参数相加 * * @param int 参数A * @param int 参数B * * @return 无返回值 */ void (^sumBlock)(int ,int ) = ^(int a,int b){ NSLog(@"%d + %d = %d",a,b,a+b); }; /** * 调用这个sumBlock的Block,得到的结果是20 */ sumBlock(10,10);
3、有参数有返回值的Block
/** * 有参数有返回值 * * @param NSString 字符串1 * @param NSString 字符串2 * * @return 返回拼接好的字符串3 */ NSString* (^logBlock)(NSString *,NSString *) = ^(NSString * str1,NSString *str2){ return [NSString stringWithFormat:@"%@%@",str1,str2]; }; //调用logBlock,输出的是 我是Block NSLog(@"%@", logBlock(@"我是",@"Block"));
Block结合typedef使用
自己定义一个Block类型,用定义的类型去创建Block,更加简单便捷。
/** * 定义了一个changeColor的Block。这个changeColor必须带一个参数,这个参数的类型必须为id类型的 * 无返回值 * @param id */ typedef void(^changeColor)(id); /** * 用上面定义的changeColor声明一个Block,声明的这个Block必须遵守声明的要求。 */ @property (nonatomic, copy) changeColor backgroundColor;
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ //声明一个颜色 UIColor *color = [UIColor redColor]; //用刚刚声明的那个Block去回调修改上一界面的背景色 self.backgroundColor(color); }
-(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]; }
iOS-block三种应用场景
- 1.把block保存成对象中的属性,在恰当的时刻调用
2.把block当成方法的参数使用,block的调用在是在方法内部,在外界写block的实现(最常用)
3.把block当成方法的返回值(比较少用)
示例1
1.在Person类中
@interface Person : NSObject @property (nonatomic,strong) void(^myBlock)(int,int); @end
2.在ViewController类中
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { int a = 12; int b = 11; Person *p = [[Person alloc] init]; p.myBlock(a,b); }
示例2
1.在Person类中
@interface Person : NSObject - (void)eat:(void(^)())block; @end @implementation Person - (void)eat:(void (^)())block { block(); } @end
2.在ViewController类中
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { // 方式1.先定义,在赋值 // void(^block)() = ^() { // NSLog(@"吃东西"); // }; // // [p eat:block]; // 方式2.直接写block [p eat:^{ NSLog(@"吃东西"); }]; }
示例3
1.在Person类中
@interface Person : NSObject - (void(^)(int))run; @end @implementation Person - (void (^)(int))run { return ^(int b){ NSLog(@"跑了--%d米",b); }; } @end
2.在ViewController类中
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { p.run(5); }