您的位置:首页 > 移动开发 > IOS开发

iOS block从浅到深的学习 以及循环引用的问题

2016-03-29 11:55 399 查看
1.第一部分  定义和使用Block,

<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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: