您的位置:首页 > 其它

block全面分析

2016-01-28 21:17 253 查看
//

// RootViewController.m

// UI12_Block传值

//

// Created by dllo on 15/11/24.

// Copyright (c) 2015年 dllo. All rights reserved.

//

#import "RootViewController.h"

#import "SecondViewController.h"

@interface RootViewController ()

@end

@implementation RootViewController

- (void)viewDidLoad {

[super viewDidLoad];

// Do any additional setup after loading the view.

self.view.backgroundColor = [UIColor whiteColor];

self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:@"Next" style:UIBarButtonItemStylePlain target:self action:@selector(rightAction:)]
autorelease];

void (^block1)(void) = ^(void) {

NSLog(@"aaa");

};

block1();

void (^block2)(NSString *) = ^(NSString *str) {

NSLog(@"%@", str);

};

block2(@"bbb");

}

- (void)rightAction:(UIBarButtonItem *)sender

{

SecondViewController *secondVC = [[SecondViewController alloc] init];

// block会引起self引用计数加一不释放,
因此定义一个不关心引用计数的局部变量rootVC

__unsafe_unretained RootViewController *rootVC =
self;

void (^colorBlock)(UIColor *) = ^(UIColor *myColor) {

rootVC.view.backgroundColor = myColor;

};

[secondVC sendBlock:colorBlock str:@"庆春是SB"];

[self.navigationController pushViewController:secondVC animated:YES];

[secondVC release];

}

- (void)didReceiveMemoryWarning {

[super didReceiveMemoryWarning];

// Dispose of any resources that can be recreated.

}

/*

#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

// Get the new view controller using [segue destinationViewController].

// Pass the selected object to the new view controller.

}

*/

@end

//

// SecondViewController.h

// UI12_Block传值

//

// Created by dllo on 15/11/24.

// Copyright (c) 2015年 dllo. All rights reserved.

//

#import <UIKit/UIKit.h>

@interface SecondViewController :
UIViewController

{

void (^_myBlock)(UIColor *);

}

- (void)sendBlock:(void (^)(UIColor *))block str:(NSString *)str;

@end

//

// SecondViewController.m

// UI12_Block传值

//

// Created by dllo on 15/11/24.

// Copyright (c) 2015年 dllo. All rights reserved.

//

#import "SecondViewController.h"

@interface
SecondViewController ()

@end

@implementation SecondViewController

- (void)dealloc

{

//
引用计数-1

Block_release(_myBlock);

[super dealloc];

}

- (void)viewDidLoad {

[super
viewDidLoad];

// Do any additional setup after loading the view.

self.view.backgroundColor = [UIColor
redColor];

UIButton *button = [UIButton
buttonWithType:UIButtonTypeCustom];

button.frame =
CGRectMake(50, 50, 50, 50);

button.backgroundColor = [UIColor
orangeColor];

[button setTitle:@"发春儿"
forState:UIControlStateNormal];

[button addTarget:self
action:@selector(buttonAction:)
forControlEvents:UIControlEventTouchUpInside];

[self.view
addSubview:button];

}

- (void)buttonAction:(UIButton *)sender

{

_myBlock([UIColor
greenColor]);

}

- (void)sendBlock:(void (^)(UIColor *))block str:(NSString *)str

{

NSLog(@"%@", str);

// block([UIColor blueColor]);

// block开空间区域不定,
出方法可能会释放, 所以用myblock在堆区复制block的空间

_myBlock = Block_copy(block);

}

- (void)didReceiveMemoryWarning {

[super
didReceiveMemoryWarning];

// Dispose of any resources that can be recreated.

}

/*

#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

// Get the new view controller using [segue destinationViewController].

// Pass the selected object to the new view controller.

}

*/

@end

//

// RootViewController.m

// UI12_Block传值

//

// Created by dllo on 15/11/24.

// Copyright (c) 2015年 dllo. All rights reserved.

//

#import "RootViewController.h"

#import "SecondViewController.h"

@interface
RootViewController ()

@end

@implementation RootViewController

- (void)viewDidLoad {

[super
viewDidLoad];

// Do any additional setup after loading the view.

self.view.backgroundColor = [UIColor
whiteColor];

self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem
alloc] initWithTitle:@"Next"
style:UIBarButtonItemStylePlain
target:self
action:@selector(rightAction:)]
autorelease];

void (^block1)(void) = ^(void) {

NSLog(@"aaa");

};

block1();

void (^block2)(NSString *) = ^(NSString *str) {

NSLog(@"%@", str);

};

block2(@"bbb");

}

- (void)rightAction:(UIBarButtonItem *)sender

{

SecondViewController *secondVC = [[SecondViewController alloc] init];

#warning block传值1 -
定义block,
并通过调用secondVC的方法将block地址传递过去

__unsafe_unretained RootViewController *rootVC =
self;

[secondVC sendBlock:^(UIColor *myColor) {

rootVC.view.backgroundColor = myColor;

} str:@"aaa"];

[self.navigationController pushViewController:secondVC animated:YES];

[secondVC release];

}

- (void)didReceiveMemoryWarning {

[super didReceiveMemoryWarning];

// Dispose of any resources that can be recreated.

}

/*

#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

// Get the new view controller using [segue destinationViewController].

// Pass the selected object to the new view controller.

}

*/

@end

//

// SecondViewController.h

// UI12_Block传值

//

// Created by dllo on 15/11/24.

// Copyright (c) 2015年 dllo. All rights reserved.

//

#import <UIKit/UIKit.h>

typedef void (^blockType)(UIColor *);

@interface SecondViewController :
UIViewController

{

#warning block传值3 -
定义实例变量,
指向传递来的block, 可供其他方法内调用block

//
也可定义成属性, 要用copy

blockType _myBlock;

}

#warning block传值2 -
声明方法,
用来接受block的地址,
同事可以顺带接收其他传递值

- (void)sendBlock:(blockType)block str:(NSString *)str;

@end

//

// SecondViewController.m

// UI12_Block传值

//

// Created by dllo on 15/11/24.

// Copyright (c) 2015年 dllo. All rights reserved.

//

#import "SecondViewController.h"

@interface
SecondViewController ()

@end

@implementation SecondViewController

- (void)dealloc

{

//
引用计数-1

#warning block传值6 -
引用计数减1

Block_release(_myBlock);

[super dealloc];

}

- (void)viewDidLoad {

[super
viewDidLoad];

// Do any additional setup after loading the view.

self.view.backgroundColor = [UIColor
redColor];

UIButton *button = [UIButton
buttonWithType:UIButtonTypeCustom];

button.frame =
CGRectMake(50, 50, 50, 50);

button.backgroundColor = [UIColor
orangeColor];

[button setTitle:@"发春儿"
forState:UIControlStateNormal];

[button addTarget:self
action:@selector(buttonAction:)
forControlEvents:UIControlEventTouchUpInside];

[self.view
addSubview:button];

}

- (void)buttonAction:(UIButton *)sender

{

#warning block传值5 =
调用block,
传递参数

_myBlock([UIColor
greenColor]);

}

- (void)sendBlock:(blockType)block str:(NSString *)str

{

NSLog(@"%@", str);

// block([UIColor blueColor]);

// block开空间区域不定,
出方法可能会释放, 所以用myblock在堆区复制block的空间

#warning block传值4 -
将rootVC中定义的block空间拷贝到堆区,
防止释放

_myBlock = Block_copy(block);

}

- (void)didReceiveMemoryWarning {

[super
didReceiveMemoryWarning];

// Dispose of any resources that can be recreated.

}

/*

#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

// Get the new view controller using [segue destinationViewController].

// Pass the selected object to the new view controller.

}

*/

@end

1、第一部分

定义和使用Block,

?
定义Block变量,就相当于定义了一个函数。但是区别也很明显,因为函数肯定是在-viewDidLoad方法外面定义,而Block变量定义在了viewDidLoad方法内部。当然,我们也可以把Block定义在-viewDidLoad方法外部,例如上面的代码块printNumBlock的定义,就在-viewDidLoad外面。

再来看看上面代码运行的顺序问题,以第(3)个myBlock距离来说,在定义的地方,并不会执行Block{}内部的代码,而在myBlock(3)调用之后才会执行其中的代码,这跟函数的理解其实差不多,就是只要在调用Block(函数)的时候才会执行Block体内(函数体内)的代码。所以上面的简单代码示例,我可以作出如下的结论,

(1)在类中,定义一个Block变量,就像定义一个函数;

(2)Block可以定义在方法内部,也可以定义在方法外部;

(3)只有调用Block时候,才会执行其{}体内的代码;

(PS:关于第(2)条,定义在方法外部的Block,其实就是文件级别的全局变量)

那么在类中定义一个Block,特别是在-viewDidLoad方法体内定义一个Block到底有什么意义呢?我表示这时候只把它当做私有函数就可以了。我之前说过,Block其实就相当于代理,那么这时候我该怎样将其与代理类比以了解呢。这时候我可以这样说:本类中的Block就相当于类自己服从某个协议,然后让自己代理自己去做某个事情。很拗口吧?看看下面的代码,

?
接着在-viewDidLoad中的代码如下,

?
看出这种写法的奇葩地方了吗?自己委托自己去实现某个方法,而不是委托别的类去实现某个方法。本类中定义的一个Block其实就是闲的蛋疼,委托自己去字做某件事情,实际的意义不大,所以你很少看见别人的代码直接在类中定义Block然后使用的,Block很多的用处是跨越两个类来使用的,比如作为property属性或者作为方法的参数,这样就能跨越两个类了。

2、第二部分

__block关键字的使用

在Block的{}体内,是不可以对外面的变量进行更改的,比如下面的语句,

?
这段代码有什么问题呢,Xcode会提示x变量错误信息:Variable is not assigning (missing __block type),这时候给int x = 100;语句前面加上__block关键字即可,如下,

?
这样在Block的{}体内,就可以修改外部变量了。

3、第三部分:Block作为property属性实现页面之间传值

需求:在ViewController中,点击Button,push到下一个页面NextViewController,在NextViewController的输入框TextField中输入一串字符,返回的时候,在ViewController的Label上面显示文字内容,

(1)第一种方法:首先看看通过“协议/代理”是怎么实现两个页面之间传值的吧,

?
接下来我们在看看ViewController文件中的内容,

?
这是通过“协议/代理”来实现的两个页面之间传值的方式。

(2)第二种方法:使用Block作为property,实现两个页面之间传值,

先看看NextViewController文件中的内容,

?
再来看看ViewController文件中的内容,

?
好了就这么多代码,可以使用Block来实现两个页面之间传值的目的,实际上就是取代了Delegate的功能。

另外,博客中的代码Sample Code可以再Github下载,如果因为Github被墙了,可以在终端使用git
clone + 完整链接,即可克隆项目到本地。

Github中的代码,可以开启两种调试模式,你需要在项目的配置文件BlockSamp-Prefix.pch中注释或者解注释下面的代码,

?
即可开启两种调试的方式,如果注释了上面的语句就是使用Delegate进行调试;否则使用Block进行调试。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: