作用就是用来保存一段代码块,在一个方法定义,在另外一个方法去调用(用的少,可以用定义方法替代,一般在 在一个类中定义,在另外一个类中去调用 用的比较多
对于初学者,block的语法格式可能比较难记,可以尝试先用快捷的方式敲出格式,再根据生成的格式填入block快捷方式:inline
<#returnType#>(^<#blockName#>)(<#parameterTypes#>) = ^(<#parameters#>) { <#statements#> };block中可以访问外面的变量
block中可以定义和外界同名的变量, 并且如果在block中定义了和外界同名的变量, 在block中访问的是block中的变量默认情况下, 不可以在block中修改外界变量的值,因为block中的变量和外界的变量并不是同一个变量如果block中访问到了外界的变量, block会将外界的变量拷贝一份到堆内存中,因为block中使用的外界变量是copy的, 所以在调用之前修改外界变量的值, 不会影响到block中copy的值
如果想在block中修改外界变量的值, 必须在外界变量前面加上__block ,那么会影响到外界变量的值
如果没有添加__block是值传递如果加上__block之后就是地址传递, 所以可以在block中修改外界变量的值
案例:点击cell,作出相应的动作,在cell里面利用block保存代码
1.在cell模型声明block属性 @property (nonatomic, strong) void(^block)(); 2.在模型里面保存代码 // 打电话 CellItem *item = [CellItem cellItem]; item.title = @"打电话"; // 定义block给它 item.block = ^{ NSLog(@"打电话"); }; 3.点击cell调用block - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { CellItem *item = self.items[indexPath.row]; if (item.block) { item.block(); } }开发中,block传值大致分为顺传和逆传
顺传:比如A控制器把值传到Push之后的B控制器,就是顺传(定义属性)
很简单,你一般只需要在在B控制器的头文件声明一个属性,A控制器拿到B控制器之后,把属性赋值,B控制器就可以拿到A传过来的值使用.逆传:从名字就可以看出,是跟顺传反过来的,就是由B控制器反过来传回去A控制器,那么,这就没那么简单了
逆传我们可以使用代理,但是开发中一般不会使用了,因为实在是比较麻烦,而且代码量很多,我们一般会使用block来代替代理,从而精简代码,看起来也比较容易理解先总结一下:传值万能步骤:A传值B,A拿到B 就能传值 B传值A,拿到B就能传值
写在前面:为什么要理解或者掌握内存?!
有一位大牛说过,你要灵活运用一个东西,就必须要知道它的内存是怎样运作,是怎么管理的,才能做到灵活运用到实际开发中
我们都知道,说到内存管理,可以分为ARC和MRC两种情况 先来补充一下知识: 如何判断当前项目是ARC,还是非ARC 1.在ARC中,不允许调用retain,release,retainCount 2.重写dealloc,ARC中不能调用[super dealloc] 怎么进入非ARC环境 : 点击工程文件 -> buildSetting -> ARC
ARC下,默认一个局部变量就是一个强指针,防止一创建就释放 block访问了一个局部变量,就会放到堆里面
* 只要访问了一个外部变量,,生命周期不是全局的,只会放在堆里面 * 只要访问了一个外部变量,,生命周期是全局的,只会放在全局区
只要在block代码块里面使用了self强引用就会导致循环引用
# 注意:只要在block的代码中,访问外部强指针对象,就会把对象强引用 - (void)viewDidLoad { [super viewDidLoad]; int a = 2; #注意:只要在block的代码中,访问外部强指针对象,就会把对象强引用 #解决循环引用:将该对象使用weak或者block修饰符修饰之后再在block中使用/或者将其中一方强制制空 xxx = nil 。 __weak typeof(self) weakSelf = self; _block = ^{ // 定义强指针的self __strong typeof(self) strongSelf = weakSelf; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"%@",strongSelf); }); NSLog(@"%d",a); }; _block(); }从上面我们需要知道的是,什么是值传递,什么是指针传递
值传递: 访问局部变量指针传递:访问生命周期全局变量而被__block修饰的局部变量,就是指针传递
那么问题来了block是存储在堆中还是栈中?
//默认情况下block存储在栈中,如果对block进行一个copy操作, block会转移到堆中 //如果block在栈中, block中访问了外界的对象,那么不会对对象进行retain操作 //但是如果block在堆中, block中访问了外界的对象,那么会对外界的对象进行一次retain //如果在block中访问了外界的对象,一定要给对象加上__block,只要加上了__block,哪怕block在堆中,也不会对外界的对象进行retain //如果是在ARC开发中就需要在前面加上__weak
好,知道了上面的知识,你就会明白这一段代码的意思,为什么要加上这一句__strong typeof(self) strongSelf = weakSelf; 我们的目的是:在要执行完那个延迟block,而且拿到对象strongSelf做完我们需要做的事情之后,modal出来的控制器才销毁 如果没有一个强引用(上面那一行代码),那么,当控制器dismiss之后就释放掉那我们就拿不到weakSelf这个对象做事情了.
只要block访问了外部变量,生命周期不是全局的(是否在代码块里面),就存放在栈里面 生命周期是全局的,block就存放在全局区
block在非ARC中必须要使用copy
在非ARC环境下,retain相当于strong,为什么block不用retain 因为在非arc中,是不会存放到堆里面,过了代码块就会被释放.再访问就会坏内存访问报错
在非ARC开发注意点:访问属性,一定要使用get,set方法,不能直接使用下划线
1.封装一个类的时候,有些时候,怎么去做由外界决定,但是由内部决定什么时候调用,把block当做一个参数去使用.
2.动画block:做什么样的动画由我们决定,但是什么时候调用由系统决定.
这里就涉及到链式编程思想了,所谓的链式编程思想: 把所有的方法调用全部通过.语法连接起来,好处:可读性非常好
mgr.add(5).add(5); 其实是分两步走,先调用mgr.add的getter,返回一个block.再跟着()实现这个block - (CalculatorManager *(^)(int))add; - (CalculatorManager *(^)(int))add { return ^(int value){ _result += value; return self; }; }用strong还是copy的问题? block 使用 copy 是从 MRC 遗留下来的“传统”,在 MRC 中,方法内部的 block 是在栈区的,使用 copy 可以把它放到堆区. ★建议:在ARC中,能用strong就用strong,因为copy内部会做很多事情
block是对象吗? 是的!苹果告诉我的^0^!文档说的很清楚的
写在最后,block之强大可谓开发利器 ------make by LJW 转载请注明出处-------转载于:https://www.cnblogs.com/ljwiOS/p/5539952.html
相关资源:JAVA上百实例源码以及开源项目