【iOS开发】block使用与理解
来源:互联网 发布:java中字符串的比较 编辑:程序博客网 时间:2024/06/17 23:40
一、使用block的好处:
(1)使用block可以改变代码从上到下的执行的顺序
(2)让代码集中在一处,避免了使用代理那样需要在不同代码中来回跳转,便于代码维护/阅读
二、block的核心用途
(1)block是用来封装一段代码,在需要的时候执行
(2)block是一种数据类型,可以当做参数传递(使用多),也可以当做返回值(用的少)
三、block的三种定义方式
(0)使用提示快速输入:
inlineblock,能够快速敲出一个block的基本结构
(1)无参数,无返回值:
<span style="font-size:14px;">void (^myBlock)() = ^ { NSLog(@"hello"); };</span>
(2)有参数,无返回值
<span style="font-size:14px;"> // 定义带参数的block // 格式:void (^block名称)(参数列表) = ^ (参数列表) { // 代码实现; } void (^sumBlock)(int, int) = ^ (int x, int y) { NSLog(@"%d", x + y); };</span>
(3)有参数,有返回值
<span style="font-size:14px;">// 定义带返回值的block // 格式:返回类型 (^block名称)(参数列表) = ^ 返回类型 (参数列表) { // 代码实现; } int (^sumBlock2)(int, int) = ^ int (int a, int b) { return a + b; };</span><span style="font-size: 18px;"></span>
四、block的用法详解
1、定义格式:返回值类型 + (^名字)+(参数列表)
2、预先封装好一段代码,合适的时候再次调用block就会执行这段代码
3、是一种数据类型,可以用来指定变量类型
<span style="font-size:14px;">- (void)downloadImage:(NSString *)urlString completion:(void (^) (UIImage *image))completion;</span>此时,completion的数据类型就是(void (^)(UIImage *image))类型的
4、可以作为方法的参数使用
(1)简单的传参,在同一个控制器中:
<span style="font-size:14px;">void myWork(void (^dayWork)()) { // 是一个预先准备好的代码,在需要的时候执行! dayWork();}void dailyWork(int day) { void (^work)() = ^{ NSLog(@"入职报道"); }; // block可以当作参数传递 myWork(work);}//调用void dailyWork(1) ;</span>
(2)复杂传参,在多个控制器之间
***WebImageManager.m文件中:
实现WebImageOperation类的的声明de方法,封装了一段代码到completion,block中,作为参数传递到WebImageOperation.m文件中使用。
<span style="font-size:14px;">[</span><span style="font-family: 'Hiragino Sans GB';"><span style="font-size:12px;">webImageOperationWithURLString</span></span><span style="font-size:14px;">:urlString completion:^(UIImage *image) {// your code }];</span>
***WebImageOperation.h文件中,声明这个方法
<span style="font-size:14px;">+ (instancetype)webImageOperationWithURLString:(NSString *)urlString completion:(void (^)(UIImage*image))completion;</span>
***WebImageOperation.m文件中:
(1)定义了一个block类型的属性:
@property(nonatomic, copy) void (^completion) (UIImage*image);
(2)调用这个方法:
<span style="font-size:14px;">+ (instancetype)webImageOperationWithURLString:(NSString *)urlString completion:(void (^)(UIImage*))completion { // block 完全就是一个参数 op.completion = completion; return op;}</span>
此时,completion这个block作为参数,从另一个控制器传过来了,并赋值给当前控制器的completion属性,以便后面使用。
五、关于block,循环引用的理解
(0)循环引用:比如控制器self强引用着block,block里面又有某个对象强引用着self
(1)block中使用到外面的对象或者self,要使用__weak来修饰
(2)因为block不确定什么时候调用,所以会强引用着需要用到的对象,防止到时候调用block的时候这个对象已经被释放了
(3)所以如果可以保证block使用的对象在block调用时一定还存在,没有被释放,就不需要使用强引用,改成__weak;
六、关于定义block时,为什么要使用copy,而不使用weak、strong
(1)首先排除weak,因为block是一个数据类型,作用类似于方法,可以封装一段代码,如果使用weak,一创建出来就被销毁了
(2)strong:strong是强指针,会对修饰的对象retain一次;block是定义在函数内部的,是局部变量,所以block对象是保存在栈区的,栈区的对象在作用域过掉之后,就应该被释放掉的,但是如果使用strong修饰的话,会导致作用域过掉,栈区的block还是不能释放,这是不对的。
(3)copy:copy修饰的对象会把该对象的地址以及内容从栈区通通拷贝一份,放到堆区,那么当block所在的作用域过掉,block从栈区被释放,但是在堆区还有保留,所以这样既可以满足block不被过早释放,也不会破坏栈区对象生命周期的管理原则。至于堆区的block什么时候释放,在ARC环境下不需要程序员考虑。
七、关于block内部使用外部变量时的问题
1、
// 在默认情况下,不允许block内部修改外部变量的数值!因为会破坏代码的可读性,不易于维护! // 在定义block的时候,在定义的那一刻,如果引用了外部变量,会对外部变量做一个copy,记录住定义block时变量的数值 // 所以在调用block之前再修改x的值,不会影响block内部的数值变化!所以打印10void demoBlock1() { int x = 10; void(^myBlock)() = ^ { NSLog(@"%d", x); }; x = 20; myBlock();}
问,打印结果多少? 10
2、
// 如果要在block中,修改外部变量的数值,需要使用 __block 修饰符号 // 定义block时,如果引用了外部使用__block的变量,block定义之后,外部变量的指针地址同样会变成堆区的地址void demoBlock2() { // 使用 __block,说明不再关心x数值的具体变化 __block int x = 10; NSLog(@"定义前 %p", &x); // 栈区 void (^myBlock)() = ^ { x = 80; NSLog(@"in block %p", &x); // 堆区 }; NSLog(@"定义后 %p", &x); // 堆区 myBlock(); NSLog(@"%d", x);}
问,打印结果多少? 80
3、区分清楚修改的是内容还是地址
void demoBlock3() { // 指针记录的是地址 NSMutableString *strM = [NSMutableString stringWithString:@"zhangsan"]; NSLog(@"定义前 %p %p", strM, &strM); void (^myBlock)() = ^ { //情况一: 修改strM指针指向的内容 [strM setString:@"lisi"]; NSLog(@"inblock %p %p", strM, &strM); //情况二: 这句代码是修改strM指针指向的地址// strM = [NSMutableString stringWithString:@"wangwu"]; }; NSLog(@"定义后 %p %p", strM, &strM); myBlock(); NSLog(@"%@", strM);}
--》可以通过内存分析来理解这两种情况:
--》block中使用外部变量总结
(1)默认情况下,没有__block修饰的局部变量,存放在栈中此时在block中使用外部变量,会copy一份变量值放到堆中,但是地址不是变量真实地址,所以block内部修改变量值无效。
(2)使用__block修饰的外部变量,block内部会把变量内容连同指向它的地址一起copy到堆中,此时变量在堆中的地址跟原来栈中是一样的,所以可以修改外部变量的值。
【by:Leo_zzp,支持原创,转载请说明出处!】
个人邮箱:15999745308@163.com,GitHub链接:MrLeoZou,期待您的交流!
0 0
- 【iOS开发】block使用与理解
- ios开发-block理解
- iOS开发-block详解与使用
- IOS(二)块语法block 的理解与使用
- iOS开发--Block的使用
- iOS开发-block 简单使用
- iOS开发:block使用逻辑
- ios开发中对block 的理解
- iOS Block 的理解与学习
- ios开发中:独立Block与内联Block
- IOS开发笔记22-block与@protocol
- iOS开发之Block简介与用法
- iOS开发 block的简单使用
- iOS开发中Block的使用
- iOS开发 ——Block使用
- iOS开发之block使用小结
- 玩转 IOS 开发 - block 使用详解
- iOS开发Delegate,Notification,Block使用心得
- CSS 3D变换
- YUV格式
- 队员匹配问题
- 11.模型驱动与令牌拦截器
- 【机器学习实验】概率编程及贝叶斯方法
- 【iOS开发】block使用与理解
- UIScrollView+UIPageControl+NSTimer实现图片的自动滑动以及用户可手动切换,UIPageControl可点击
- xcode6 添加Prefix Header
- HLJOJ1214(最短路)
- Sublime Text2 的使用(一)
- GLSL基础
- Shine OpenCart 自适应 多用途主题模板 ABC-0021
- 几年的php程序生涯,以及莫名的恐慌
- android APK静默安装