标签:
1.Block的声明: 返回值类型(^block名称)(参数)
例如:声明一个无参数无返回值的block:
// 声明:返回值(^block变量名)(参数) void(^block)();
2.Block的定义:
void(^block1)() = ^(){ NSLog(@"调用block1"); };
void(^block2)() = ^{ };
int(^block3)() = ^int{//int可以省略 return 2; };
3.Block的作用:保存一段代码,在调用Block的时候执行.
4.Block的调用:block名(参数);
// 调用Block,就会去查看Block所保存代码 block1();
5.Xcode快捷生成block的方式:inlineBlock
<#returnType#>(^<#blockName#>)(<#parameterTypes#>) = ^(<#parameters#>) { <#statements#> };
6.Block起别名:
// BlockType就是类型别名 typedef void(^BlockType)();
7.Block定义属性:
// Block怎么声明.就怎么定义属性 // block:属性名 @property (nonatomic ,strong) void(^block)();
例:新建一个CellItem作为TableViewController的模型
#import <Foundation/Foundation.h> @interface CellItem : NSObject @property (nonatomic ,strong) void(^block)(); @property (nonatomic ,strong) NSString *title; @end @implementation CellItem @end
#import <UIKit/UIKit.h> @interface TableViewController : UITableViewController @end #import "CellItem.h" // tableView:打电话,发短信,发邮件 @interface TableViewController () @property (nonatomic ,strong) NSArray *cellArr; @end @implementation TableViewController - (void)viewDidLoad { [super viewDidLoad]; // 打电话 CellItem *item = [[CellItem alloc] init]; item.title = @"打电话"; item.block = ^{ NSLog(@"打电话"); }; // 发短信 CellItem *item1 = [[CellItem alloc] init]; item1.title = @"发短信"; item1.block = ^{ NSLog(@"发短信"); }; // 发邮件 CellItem *item2 = [[CellItem alloc] init]; item2.title = @"发邮件"; item2.block = ^{ NSLog(@"发邮件"); }; self.cellArr = @[item,item1,item2]; } #pragma mark - Table view data source - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.cellArr.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *ID = @"cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID]; } cell.textLabel.text = [self.cellArr[indexPath.row] title]; return cell; } // 点击cell就会调用 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { CellItem *item = self.cellArr[indexPath.row]; if (item.block) { item.block(); } } @end
数据传值分顺传和逆传.
假设:A控制器push(modal)到B控制器,若A要给B传值,则此种传值方式为顺传;B给A传值则为逆传.
开发中,大家比较熟悉的方法:顺传--->定义属性;逆传--->使用代理.
下文介绍,使用Block替换代理实现数据逆传.
#import <UIKit/UIKit.h> @class ModalViewController; @protocol ModalViewControllerDelegate <NSObject> @optional // 代理方法:想要告诉代理做什么事情 - (void)modalViewController:(ModalViewController *)modalVc receiveStr:(NSString *)str; @end @interface ModalViewController : UIViewController @property (nonatomic, weak) id<ModalViewControllerDelegate> delegate; @end @implementation ModalViewController - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { // 传值给ViewController if ([self.delegate respondsToSelector:@selector(modalViewController:receiveStr:)]) { [self.delegate modalViewController:self receiveStr:@"123"]; } } @end
#import <UIKit/UIKit.h> @interface ViewController : UIViewController @end #import "ModalViewController.h" @interface ViewController ()<ModalViewControllerDelegate> @end @implementation ViewController - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { ModalViewController *modalVc = [[ModalViewController alloc] init]; modalVc.delegate = self; modalVc.view.backgroundColor = [UIColor yellowColor]; [self presentViewController:modalVc animated:YES completion:nil]; } #pragma mark -ModalViewControllerDelegate - (void)modalViewController:(ModalViewController *)modalVc receiveStr:(NSString *)str { NSLog(@"接收到值%@",str); } @end
#import <UIKit/UIKit.h> @interface ModalViewController : UIViewController @property (nonatomic ,strong) void(^valueBlock)(NSString *value); @end @implementation ModalViewController - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { if (self.valueBlock) { self.valueBlock(@"123"); } } @end
#import <UIKit/UIKit.h> @interface ViewController : UIViewController @end #import "ModalViewController.h" @implementation ViewController - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { ModalViewController *modalVc = [[ModalViewController alloc] init]; modalVc.valueBlock = ^(NSString *value){ NSLog(@"接收到%@",value); }; modalVc.view.backgroundColor = [UIColor yellowColor]; [self presentViewController:modalVc animated:YES completion:nil]; } @end
首先需要搞清楚一个问题:block是对象吗?
苹果官方文档告诉你,没错,她就是对象.这样我们可以通过%@来打印她.
1.在非ARC中:
@interface ViewController () @property (nonatomic, copy) void(^block)(); @end - (void)viewDidLoad { [super viewDidLoad]; int a = 0; void(^block)() = ^{ NSLog(@"调用block"); NSLog(@"%d",a); }; self.block = block; NSLog(@"block - %@",block);//block - <__NSStackBlock__: 0x7fff5b9fa9c8> [栈] NSLog(@"self.block - %@",self.block);// self.block - <__NSMallocBlock__: 0x7fd2e0418310> [堆] }
@interface ViewController () @property (nonatomic, copy) void(^block)(); @end - (void)viewDidLoad { [super viewDidLoad]; int a = 0; void(^block)() = ^{ NSLog(@"调用block"); //NSLog(@"%d",a); }; self.block = block; NSLog(@"block - %@",block); //block - <__NSGlobalBlock__: 0x105d01080> NSLog(@"self.block - %@",self.block);//self.block - <__NSGlobalBlock__: 0x105d01080> }
@interface ViewController () @property (nonatomic, copy) void(^block)(); @end static NSString *str = @"iOS"; - (void)viewDidLoad { [super viewDidLoad]; int a = 0; void(^block)() = ^{ NSLog(@"调用block"); //NSLog(@"%d",a); NSLog(@"%@",str); }; self.block = block; NSLog(@"block - %@",block); //block - <__NSGlobalBlock__: 0x100b8e080> NSLog(@"self.block - %@",self.block); //block - <__NSGlobalBlock__: 0x100b8e080> }
注意: 在非ARC中.不能使用retain引用block,因为block访问外部局部变量时,retain不会把block放在堆里面(仍然存放在栈里),生命周期没有得到延长.
在非ARC中使用copy,才会把block放在堆里面.
@interface ViewController () //@property (nonatomic, copy) void(^block)(); @property (nonatomic, retain) void(^block)(); @end - (void)viewDidLoad { [super viewDidLoad]; int a = 0; void(^block)() = ^{ NSLog(@"调用block"); NSLog(@"%d",a); //NSLog(@"%@",str); }; self.block = block; NSLog(@"block - %@",block);// block - <__NSStackBlock__: 0x7fff55d5b9c8> NSLog(@"self.block - %@",self.block);//self.block - <__NSStackBlock__: 0x7fff55d5b9c8> }
2. ARC环境:
可以使用strong去引用
@interface ViewController () @property (nonatomic, strong) void(^block)(); @end - (void)viewDidLoad { [super viewDidLoad]; int a = 0; // ARC中,默认局部对象变量都是强指针 void(^block)() = ^{ NSLog(@"调用block"); NSLog(@"%d",a); }; self.block = block; NSLog(@"%@",block);//<__NSMallocBlock__: 0x7f9218c3b810> NSLog(@"%@",self.block);// <__NSMallocBlock__: 0x7f86fa6133d0> }
归纳:只要block访问的变量是整个app运行过程中都存在的变量,那么block肯定存放在全局区.
Block循环引用,跟block调用没有关系
block只要访问外部强指针对象变量,就会对这个变量进行强引用.
1 #import <UIKit/UIKit.h> 2 3 @interface ModalViewController : UIViewController 4 5 @end 6 7 @interface ModalViewController () 8 9 @property (nonatomic ,strong) void(^block)(); 10 11 @end 12 13 @implementation ModalViewController 14 15 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 16 { 17 [self dismissViewControllerAnimated:YES completion:nil]; 18 } 19 20 - (void)dealloc 21 { 22 NSLog(@"%@对象销毁",self); 23 } 24 25 - (void)viewDidLoad { 26 [super viewDidLoad]; 27 28 // Block循环引用,跟block调用没有关系 29 // block只要访问外部强指针对象变量,就会对这个变量进行强引用. 30 31 self.block = ^{ 32 NSLog(@"延迟打印%@",self); 33 }; 34 35 self.block(); 36 } 37 @end
1 #import <UIKit/UIKit.h> 2 3 @interface ViewController : UIViewController 4 5 @end 6 7 #import "ModalViewController.h" 8 9 @implementation ViewController 10 11 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 12 { 13 ModalViewController *modalVc = [[ModalViewController alloc] init]; 14 15 modalVc.view.backgroundColor = [UIColor redColor]; 16 17 //self.presentedViewController强引用modalVc 18 [self presentViewController:modalVc animated:YES completion:nil]; 19 } 20 @end
点击viewController的屏幕modal出来ModalViewController,然而再点击ModalViewController的屏幕会发现ModalViewController并没有被销毁.
原因:发生了循环引用.block只要访问外部强指针对象变量(self也就是ModalViewController),就会对这个变量进行强引用.而ModalViewController对block也进行着强引用.
解决办法:使用__weak修饰符.让block对modalVc进行弱引用.
1 - (void)viewDidLoad { 2 [super viewDidLoad]; 3 4 // Block循环引用,跟block调用没有关系 5 // block只要访问外部强指针对象变量,就会对这个变量进行强引用. 6 __weak typeof(self) weakSelf = self; 7 8 self.block = ^{ 9 10 NSLog(@"延迟打印%@",weakSelf); 11 12 }; 13 14 //self.block(); 15 } 16 @end
需求:在block中处理延时操作,需要访问modalVc即使马上dismiss控制器,保证仍能访问.即实现dismiss延迟销毁控制器.
1 - (void)viewDidLoad { 2 [super viewDidLoad]; 3 4 // Block循环引用,跟block调用没有关系 5 // block只要访问外部强指针对象变量,就会对这个变量进行强引用. 6 __weak typeof(self) weakSelf = self; 7 8 self.block = ^{ 9 10 __strong typeof(weakSelf) strongSelf = weakSelf; 11 12 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2* NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 13 // 引用的为内部强指针 14 NSLog(@"延迟打印%@",strongSelf); 15 16 }); 17 18 }; 19 20 self.block(); 21 }
2016-04-10 20:08:19.918 06-Block循环引用[7884:212378] 延迟打印<ModalViewController: 0x7f9a31e1ebe0>
2016-04-10 20:08:19.936 06-Block循环引用[7884:212378] <ModalViewController: 0x7f9a31e1ebe0>对象销毁
self.block();执行完并且dismiss,仍然有系统的强指针指向after那个block块,保证modalVc不被立即销毁.当延时block快执行完毕,strongSelf指针不再强引用modalVc,此时modalVc控制器对象才能销毁.
1 - (void)viewDidLoad { 2 [super viewDidLoad]; 3 4 // 如果局部变量被static,__block修饰,那么都是指针传递 5 // 全局变量.也是指针传递 6 __block int a = 5; 7 8 // 默认局部变量 在block中 是 值传递 9 void(^block)() = ^{ 10 11 NSLog(@"%d",a);//10 12 }; 13 14 a = 10; 15 16 block(); 17 }
1 int a = 5; 2 3 @implementation ViewController 4 5 - (void)viewDidLoad { 6 [super viewDidLoad]; 7 8 // 如果局部变量被static,__block修饰,那么都是指针传递 9 // 全局变量.也是指针传递 10 //__block int a = 5; 11 12 // 默认局部变量 在block中 是 值传递 13 void(^block)() = ^{ 14 15 NSLog(@"%d",a);//10 16 }; 17 18 a = 10; 19 20 block(); 21 } 22 23 @end
1 - (void)viewDidLoad { 2 [super viewDidLoad]; 3 4 // 如果局部变量被static,__block修饰,那么都是指针传递 5 // 全局变量.也是指针传递 6 int a = 5; 7 8 // 默认局部变量 在block中 是 值传递 9 void(^block)() = ^{ 10 11 NSLog(@"%d",a);//5 12 }; 13 14 a = 10; 15 16 block(); 17 }
其实Block作为方法的参数使用,我们开发中经常使用.
例如:
[UIView animateWithDuration:1 animations:^{ }];
只要方法参数带有^,就表示把block当做参数去使用.
以上的例子中,把block当做参数去使用,block并不是我们调用,而是系统调用.
使用场景: 当自己封装一个类的时候,有些事情比如怎么做由外部决定,但是什么时候去做,由内部决定,这时候采取使用block.
需求:封装一个计算器,提供一个计算方法,怎么计算由外界去决定,什么时候计算,自己管理.
1 #import <Foundation/Foundation.h> 2 3 @interface CalculateManager : NSObject 4 5 /** 保存计算的结果 */ 6 @property (nonatomic, assign) int result; 7 8 /** 9 * 计算 10 * 11 * @param block 交待怎么计算的block 12 */ 13 - (void)calculate:(int(^)(int))block; 14 15 @end 16 17 @implementation CalculateManager 18 19 - (void)calculate:(int (^)(int))block 20 { 21 self.result = block(self.result); 22 } 23 @end
1 #import <UIKit/UIKit.h> 2 3 @interface ViewController : UIViewController 4 5 @end 6 7 8 #import "CalculateManager.h" 9 10 @interface ViewController () 11 12 @end 13 14 @implementation ViewController 15 16 - (void)viewDidLoad { 17 [super viewDidLoad]; 18 19 // 创建计算器管理者 20 CalculateManager *mgr = [[CalculateManager alloc] init]; 21 22 [mgr calculate:^(int result){ 23 // 计算 24 result += 5; 25 result *= 2; 26 27 return result; 28 }]; 29 30 NSLog(@"%d",mgr.result); 31 32 } 33 @end
其实Block作为方法的返回值使用,我们开发中可能很多人都用过.
例如:目前最流行的AutoLayout框架Masonry
[targetView mas_makeConstraints:^(MASConstraintMaker *make) { make.bottom.equalTo(self.view).offset(-20); make.leading.equalTo(self.view).offset(20); make.size.mas_equalTo(CGSizeMake(100, 100)); }];
一般调用方法后面接(),就是把block当做返回值去用.
编程思想:
链式编程:把方法的调用 通过.语法 链接起来,可读性非常好.
#import <Foundation/Foundation.h> @interface CalculateManager : NSObject /** 保存计算的结果 */ @property (nonatomic, assign) int result; /** * 加一个值返回一个计算管理对象 */ - (CalculateManager *)add:(int)value; /** * 返回一个 带有整形参数返回值是计算管理对象的 block */ - (CalculateManager *(^)(int))add; @end @implementation CalculateManager - (CalculateManager *)add:(int)value { self.result += value; return self; } - (CalculateManager *(^)(int))add { return ^(int value){ self.result += value; return self; }; } @end
#import <UIKit/UIKit.h> @interface ViewController : UIViewController @end #import "CalculateManager.h" /* 需求:封装计算器类,提供加号方法,用于处理加法计算. */ @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; CalculateManager *mgr = [[CalculateManager alloc] init]; [[[[[mgr add:5] add:5] add:5] add:5] add:5]; mgr.add(5).add(5).add(5).add(5).add(5); NSLog(@"%d",mgr.result);//50 }
标签:
原文地址:http://www.cnblogs.com/wm-0818/p/5374666.html