iOS block从浅到深的学习 以及循环引用的问题
2016-03-29 11:55
399 查看
1.第一部分 定义和使用Block,
定义Block变量, 就相当于定义了一个函数, 但是区别也很明显, 因为函数肯定在-viewDidload方法外面定义, 而Block变量定义在了viewDidload方法内部, 当然,我们也可以把Block定义在外部,
再来看看上面代码运行的顺序问题, 只有调用block的时候才会执行block块内部的代码,这根函数差不多,所以有如下结论:
1.在类中,定义一个Block变量, 就像定义一个函数
2.Block可以定义在方法内部, 也可以定义在方法外部
3. 只有调用block时候, 才会执行block体内的代码
那么在类中定义一个Block, 可以当做一个私有函数, Block相当于代理, 本类中Block就相当于类自己服从某个协议, 然后让自己代理自己去做某个事情,
Block很多的用处是跨越两个类来使用的, 比如作为property属性或者作为方法的参数, 这样就可以跨越两个类
2.第二部分 Block循环引用的问题
_block关键字的使用
在block代码块中是不可以对外面的变量进行更改的,比如下面的语句
__weak关键字的使用
block在copy时都会对block内部用到的对象进行强引用使对象引用计数加1,对block使用不当就会引起循环引用的问题,一帮表现为, 某个类将block作为自己的属性变量, 然后该类在block的方法里面又使用了该类本身, 简单来说就是self.block = (^Type var){self something; 在block中使用了self} ;block这种循环引用会被编译器捕捉到及时提醒,
只有你在block代码块里用到了self里面的东西,就会出现循环引用的问题
ARC环境下可以通过使用__weak声明一个代替self的新变量代替原来的self,我们可以命名为weakSelf.通过这种方式告诉block,不要再block内部对self进行强制strong引用
3.第三部分:Block作为property属性实现页面之间传值
需求:在ViewController中,点击Button,push到下一个页面NextViewController,在NextViewController的输入框TextField中输入一串字符,返回的时候,在ViewController的Label上面显示文字内容
(1)第一种方法:首先看看通过“协议/代理”是怎么实现两个页面之间传值的吧,
这是通过协议代理来实现两个页面之间传值的方式
2)第二种方法:使用Block作为property,实现两个页面之间传值,
先看看NextViewController文件中的内容,
再来看看ViewController文件中的内容,
这几行代码就可以用Block实现俩个VC的传值目的,实际上就取代了Delegate的功能
部分内容来自:http://my.oschina.net/leejan97/blog/268536
<span style="font-size:14px;">// 1. 定义无参无返回值得Block void (^printBlock) () = ^() { NSLog(@"no number"); }; printBlock(); // 2. 定义名字为myBlock的代码块, 返回值类型为int int multiplier = 4; int (^ myBlock)(int) = ^(int num) { return num * multiplier; }; myBlock(5); // 3. 一个有参数没有返回值得block void (^ printsBlock)(int, int) = ^(int num1, int num2) { NSLog(@"%d", num1 + num2); }; printsBlock(2, 34);</span>
定义Block变量, 就相当于定义了一个函数, 但是区别也很明显, 因为函数肯定在-viewDidload方法外面定义, 而Block变量定义在了viewDidload方法内部, 当然,我们也可以把Block定义在外部,
再来看看上面代码运行的顺序问题, 只有调用block的时候才会执行block块内部的代码,这根函数差不多,所以有如下结论:
1.在类中,定义一个Block变量, 就像定义一个函数
2.Block可以定义在方法内部, 也可以定义在方法外部
3. 只有调用block时候, 才会执行block体内的代码
那么在类中定义一个Block, 可以当做一个私有函数, Block相当于代理, 本类中Block就相当于类自己服从某个协议, 然后让自己代理自己去做某个事情,
Block很多的用处是跨越两个类来使用的, 比如作为property属性或者作为方法的参数, 这样就可以跨越两个类
2.第二部分 Block循环引用的问题
_block关键字的使用
在block代码块中是不可以对外面的变量进行更改的,比如下面的语句
<span style="font-size:14px;">// 用__blok修饰变量, 那么在block块内可修改该变量 __block int a = 100; int (^ BlockOnew)(int) = ^(int num) { a += num; return a; }; BlockOnew(4);</span>
__weak关键字的使用
block在copy时都会对block内部用到的对象进行强引用使对象引用计数加1,对block使用不当就会引起循环引用的问题,一帮表现为, 某个类将block作为自己的属性变量, 然后该类在block的方法里面又使用了该类本身, 简单来说就是self.block = (^Type var){self something; 在block中使用了self} ;block这种循环引用会被编译器捕捉到及时提醒,
只有你在block代码块里用到了self里面的东西,就会出现循环引用的问题
ARC环境下可以通过使用__weak声明一个代替self的新变量代替原来的self,我们可以命名为weakSelf.通过这种方式告诉block,不要再block内部对self进行强制strong引用
<span style="font-size:14px;">// 用__weak修饰self 避免循环引用 __weak typeof(self) weakSelf = self; int (^ BlockOnew)(int) = ^(int num) { UIView *view = weakSelf.view; };</span>
3.第三部分:Block作为property属性实现页面之间传值
需求:在ViewController中,点击Button,push到下一个页面NextViewController,在NextViewController的输入框TextField中输入一串字符,返回的时候,在ViewController的Label上面显示文字内容
(1)第一种方法:首先看看通过“协议/代理”是怎么实现两个页面之间传值的吧,
<span style="font-size:14px;">//NextViewController是push进入的第二个页面 //NextViewController.h 文件 //定义一个协议,前一个页面ViewController要服从该协议,并且实现协议中的方法 @protocol NextViewControllerDelegate <NSObject> - (void)passTextValue:(NSString *)tfText; @end @interface NextViewController : UIViewController @property (nonatomic, assign) id<NextViewControllerDelegate> delegate; @end //NextViewController.m 文件 //点击Button返回前一个ViewController页面 - (IBAction)popBtnClicked:(id)sender { if (self.delegate && [self.delegate respondsToSelector:@selector(passTextValue:)]) { //self.inputTF是该页面中的TextField输入框 [self.delegate passTextValue:self.inputTF.text]; } [self.navigationController popViewControllerAnimated:YES]; }</span>
<span style="font-size:14px;">//ViewController.m 文件 @interface ViewController ()<NextViewControllerDelegate> @property (strong, nonatomic) IBOutlet UILabel *nextVCInfoLabel; @end //点击Button进入下一个NextViewController页面 - (IBAction)btnClicked:(id)sender { NextViewController *nextVC = [[NextViewController alloc] initWithNibName:@"NextViewController" bundle:nil]; nextVC.delegate = self;//设置代理 [self.navigationController pushViewController:nextVC animated:YES]; } //实现协议NextViewControllerDelegate中的方法 #pragma mark - NextViewControllerDelegate method - (void)passTextValue:(NSString *)tfText { //self.nextVCInfoLabel是显示NextViewController传递过来的字符串Label对象</span>
这是通过协议代理来实现两个页面之间传值的方式
2)第二种方法:使用Block作为property,实现两个页面之间传值,
先看看NextViewController文件中的内容,
<span style="font-size:14px;">//NextViewController.h 文件 @interface NextViewController : UIViewController @property (nonatomic, copy) void (^NextViewControllerBlock)(NSString *tfText); @end //NextViewContorller.m 文件 - (IBAction)popBtnClicked:(id)sender { if (self.NextViewControllerBlock) { self.NextViewControllerBlock(self.inputTF.text); } [self.navigationController popViewControllerAnimated:YES]; }</span>
再来看看ViewController文件中的内容,
<span style="font-size:14px;">- (IBAction)btnClicked:(id)sender { NextViewController *nextVC = [[NextViewController alloc] initWithNibName:@"NextViewController" bundle:nil]; nextVC.NextViewControllerBlock = ^(NSString *tfText){ [self resetLabel:tfText]; }; [self.navigationController pushViewController:nextVC animated:YES]; } #pragma mark - NextViewControllerBlock method - (void)resetLabel:(NSString *)textStr { self.nextVCInfoLabel.text = textStr; }</span>
这几行代码就可以用Block实现俩个VC的传值目的,实际上就取代了Delegate的功能
部分内容来自:http://my.oschina.net/leejan97/blog/268536
相关文章推荐
- iOS每日一记---------之 iOS开发编码建议与规范
- iOS本地存储0--plist归档
- iOS 应用程序 Crash文件的理解与分析
- iOS系统的单例类
- iOS隐藏状态栏
- iOS开发提醒用户更新软件
- iOS 学习笔记五 【2016年百度地图定位详细使用方法】
- oc类的创建与使用与数组的四种遍历示例
- iOS开发 - 广播(跑马灯)的实现
- 超全!整理常用的iOS第三方资源
- iOS 最新版9.3 disk image
- ios优秀开发者笔记汇总
- iOS调试—断点调试
- iOS实时通讯之socket
- 需求 - 5 - 悬浮框 - 2
- ios 静态库/动态库/framework
- ios 延时加载
- ios学习--NSAttributedString用法 & NSMutableParagraphStyle 来创建多姿多彩的文本
- iOS开发者程序许可协议
- iOS中OpenURL的使用