Block的使用--页面传值方法及探究
2015-07-27 18:02
141 查看
上一篇讲了Block的简单实用,这一篇则是讲述Block的最经常也是比较简单的用法,个人认为这是block相对其他页面传值方式比较好的一个用处。也顺便总结下这两天对Block的理解的一些注意点。
这一篇博客我只讲一下Block的一般页面传值的使用方法还有探究下其原理。话不多说直接上代码:
这里效果大致也就如下:
![](http://img.blog.csdn.net/20150727155037293)
这种情况就会产生循环引用
1、被执行copy方法
2、作为方法的返回值
3、将Block赋值给由__strong修饰符的id对象或者Block类型的成员变量
4、在方法名中含有usingBlock的Cocoa框架方法或者GDC的API中传递的时候(这一点我也不是很理解)
Demo地址:https://github.com/ChenNan-FRAM/TransferDataDemo
对于页面传值这种情况,我们一般在程序里有几种处理的方法。 1、设置Delegate 2、使用NotificationCenter 3、使用Block 4、KVO页面传值 5、NSUserDefault等文件存储机制做中间介质传递(但比较浪费,用在页面传值上几率很低)
这一篇博客我只讲一下Block的一般页面传值的使用方法还有探究下其原理。话不多说直接上代码:
方法以及使用
///第一个页面中: #import "ViewController.h" #import "NextVC.h" @interface ViewController ()<NextVCDelegate>{ UILabel *_useBlockText;//显示文字 UIButton *_toNextVC_Block;//进入下个页面 } @end ///将按钮与显示label放到view上,这里省略。具体可到末尾看我Demo里的源码 /** * @brief 按钮事件:进入下个页面,指定Block回调函数 */ - (void)toNext_Block { NextVC *next = [[NextVC alloc]init]; // 指定回调函数 next.NextVCBlock = ^(NSString *text){ _useBlockText.text = [NSString stringWithFormat:@"I'm from block : %@", text]; }; [self.navigationController pushViewController:next animated:YES]; }
//第二个页面 //.h头文件 @interface NextVC : UIViewController @property (nonatomic, copy) void(^NextVCBlock)(NSString *text); @end //.m实现文件 #import "NextVC.h" @interface NextVC () { UIButton *_useBlock; UITextField *_text; } ///将按钮与显示label放到view上,这里省略。具体可到末尾看我Demo里的源码 /** * @brief 使用Block进行页面传值 */ - (void)tranferUseBlock { //传值部分 if (self.NextVCBlock) self.NextVCBlock(_text.text); [self.navigationController popViewControllerAnimated:YES]; } @end
这里效果大致也就如下:
传递流程探究
在一个类中定义一个Block,在另一个类怎么得到消息改变的呢。流程分析:通过打断点以及尝试总算明白了block在页面间传值的一个流程。 我们在第二个页面中声明了一个block类型的属性NextVCBlock: @property (nonatomic, copy) void(^NextVCBlock)(NSString *text); 而我们在第一个页面实例化了NextVC的对象: NextVC *next = [[NextVC alloc]init]; 并且实现了这个NextVCBlock: next.NextVCBlock = ^(NSString *text){ _useBlockText.text = ...; }; 当我们在第二个页面中调用了该Block: self.NextVCBlock(_text.text); 这会自动把Block复制到堆上,然后触发了next.NextVCBlock内部实现代码。
外部变量的使用权限问题
为了优化存储,Block变量与Block本身一开始都是存储于栈上的,跟局部变量类似。在函数体中定义的局部变量通常都是存储在栈内,全局变量/静态变量一般放在堆上。block在引用外部变量时可以是readonly。只能读不能改,如果你想修改局部变量,则应该使用__block对该变量进行修饰。比如__block int sum = 10;
原因分析: 这是因为block事实上是指向一个结构体的指针,其内部的代码会被声称一个函数。 内部代码在使用外部的变量sum时,传递的只是一个值,而当使用了__block修饰后,传递过来的则是变脸sum的地址。
循环引用的问题(Memory recycle)
比如我们刚刚上面的- (void)toNext_Block这个函数中,如果我们加入一句
NSLog(@"%@",next.description);,也就是:
NextVC *next = [[NextVC alloc]init]; next.NextVCBlock = ^(NSString *text){ _useBlockText.text = [NSString stringWithFormat:@"I'm from block : %@", text]; NSLog(@"%@",next.description); };
这种情况就会产生循环引用
原因分析: 因为当这个函数生命周期结束的时候,系统想释放next,但释放next首先要释放NextVCBlock这个变量. 而我们在NextVCBlock中又强引用了next这个对象。 主要原因是所有局部变量在默认情况下的修饰符都为__strong。 解决方法: 你以为这里只需要在NextVC前加__weak即可解决吗?事实却不是如此,因为如果我们使用: __weak NextVC *next = [[NextVC alloc]init]; next一声明马上就被系统自动回收了,所以后面的使用是不执行的。最好的解决方法应该是: NextVC *next = [[NextVC alloc]init]; __weak typeof(NextVC) *weakNext = next; 然后使用weakNext代替next: weakNext.NextVCBlock = ^(NSString *text){ _useBlockText.text = [NSString stringWithFormat:@"I'm from block : %@", text]; NSLog(@"I'm weakNext == %@",weakNext.description); };
在ARC环境下,以下几种情况Block会自动从栈复制到堆上:
(来源于网上一个帖子所说)1、被执行copy方法
2、作为方法的返回值
3、将Block赋值给由__strong修饰符的id对象或者Block类型的成员变量
4、在方法名中含有usingBlock的Cocoa框架方法或者GDC的API中传递的时候(这一点我也不是很理解)
这里有个知识点可以扩展下: 栈的优点是创建速度快、管理简单。有严格的生命周期。 因为是先进后出队列,所以效率高也不会有碎片问题。由系统释放。 堆是动态分配的,可由程序员自行控制释放。 但是是根据指针指向一串不连续的内存,空间比较大但频繁的new/release肯定会造成内存空间的更加不连续,即内存碎片化。 效率上: 堆:char *s1 = "Hellow Word";是在编译时就确定的; 栈:char s1[] = "Hellow Word"; 是在运行时赋值的; 再比如NSString与NSMutableString的对象,前者是放在栈中,后者是放在堆上。创建方法也不同,比如 NSString *str = @"hello"; NSMutableString *mutableStr = [[NSMutableString alloc] initWithString:@"hello"]; 前者是直接在栈上创建,后者是需要分配空间再进行初始化。
Demo地址:https://github.com/ChenNan-FRAM/TransferDataDemo
相关文章推荐
- Android、iOS大不同——生命周期
- SQL Server 2008 R2 安装出错:Could not open key
- 了解HTML5和“她”的 API (三)
- flash播放mp4插件轻松搞定播放视频问题
- Cocos2d-x事件分发机制学习笔记 分类: cocos2d代码编写 2015-07-27 18:02 6人阅读 评论(0) 收藏
- Cocos2d-x中,onEnter与init的区别
- Java笔记之线程池
- 【转载】初学makefile
- Python去除多余空格
- H3C 链路聚合协议
- cas login-webflow.xml分析。关于TGT何时生成和存储。
- ssh 反向代理
- 网络爬虫heritrix 3.1 在Windows上的搭建与使用方法说明
- 修复Xcode升级错误 — PCH File Error
- httpwebreqeust读取httponly的cookie
- [考试维护]时隔半年的考试系统
- HashMap的实现
- C++静态成员函数不能调用非静态成员变量
- linux 获取当前目录名的方法
- HDU 1150 Machine Schedule(最小点覆盖)