block在iOS日常开放中已经越来越受欢迎了,小结一下,填补之前遇到的坑
block
- block的作用:是用来保存一段代码片段
- block声明: 返回值 (^变量名)(参数);
- block的类型:
类型为:int(^)(NSString *)
int(^block)(NSString *) = ^(NSString *name) {
};
- block的定义(3中方式)= ^(参数){}
//方式1 正常
void(^myBlock1)() = ^(){
NSLog(@"第一种方式");
};
//方式2 如果没有参数,参数可以隐藏,如果有参数,定义的时候,必须要写参数,而且必须要有参数变量名
void(^myBlock2)(int) = ^(int a){
NSLog(@"第二种方式");
};
//方式3 block返回可以省略,不管有没有返回值,都可以省略
int(^myBlock3)() = ^int{
return 3;
};
- block的调用
//比如说调用第一个
myBlock1();
- block是对象,
- 只要block没有引用外部局部变量,block放在全局区
- MRC: block在MRC环境下
- block:只要引用外部局部变量,block放在栈里面
- block只能使用copy,不能使用retain,使用retain,block还在栈里面,在访问的时候内存销毁,会报坏内存错误
- ARC: block在ARC环境下
- 只要block引用外部局部变量,block放在堆里面
- block使用strong修饰,最好不用copy
block使用场景
1、定义在一个方法在另外一个方法中调用(不常用)
2、在一个类中定义,在另外一个类中调用(常用),用block保存代码到模型中
例子:在控制器里面定义一个tableView,在定义一个模型model,
#import "ViewController.h"
#import "cellModel.h"
@interface ViewController ()<UITableViewDelegate,UITableViewDataSource>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic, strong) NSArray *itemModels;
@end
- (void)viewDidLoad {
[super viewDidLoad];
//模型
cellModel *model1 = [cellModel itemWithString:@"标题1"];
model1.cellBlock = ^{
NSLog(@"点击标题1了");
};
cellModel *model2 = [cellModel itemWithString:@"鸟啼2"];
model2.cellBlock = ^{
NSLog(@"点击标题2了");
};
cellModel *model3 = [cellModel itemWithString:@"标题3"];
model3.cellBlock = ^{
NSLog(@"点击标题3了");
};
self.itemModels = @[model1,model2,model3];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 3;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *ID = @"ID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:ID];
}
cellModel *model = self.itemModels[indexPath.row];
cell.textLabel.text = model.title;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
cellModel *model = self.itemModels[indexPath.row];
//判断是否存在
if (model.cellBlock) {
model.cellBlock();
}
}
### 模型###
#import <Foundation/Foundation.h>
@interface cellModel : NSObject
/** 名称*/
@property (nonatomic, strong) NSString *title;
/** 保存代码的block */
@property (nonatomic, strong) void(^cellBlock)(void);
+(instancetype)itemWithString:(NSString *)title;
@end
#import "cellModel.h"
@implementation cellModel
+(instancetype)itemWithString:(NSString *)title {
cellModel *model = [[self alloc] init];
model.title = title;
return model;
}
@end
打印结果
block打印.pngblock变量传递
//如果是局部变量的话,block是值传递
- (void)viewDidLoad {
[super viewDidLoad];
int a = 3;
//如果是局部变量的话,block是值传递
void(^block)(void)=^{
NSLog(@"%zd",a);
};
//调用
block();
打印的结果:a= 3;
//如果是静态变量/全局变量/__block修饰的变量,block是指针传递
//全局变量
int a = 3;
- (void)viewDidLoad {
[super viewDidLoad];
//static int a = 3; //静态变量
__block int a = 3;
//如果是局部变量的话,block是值传递
void(^block)(void)=^{
NSLog(@"%zd",a);
};
a = 5;
block();
打印的结果是:a = 5;
}
block传值
//block传值也是普遍使用的 和delegate传值其他效果是一样的(都是逆传)
//有2个控制器VC
*************************例子************************
#import "ViewController.h"
#import "BlockValueVC.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor redColor];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
BlockValueVC *modalVc = [[BlockValueVC alloc] init];
modalVc.view.backgroundColor = [UIColor brownColor];
modalVc.block = ^(NSString *value) {
NSLog(@"传值结果:%@",value);
};
// 跳转
[self presentViewController:modalVc animated:YES completion:nil];
}
//在BlockValueVC控制器中定义block
#import <UIKit/UIKit.h>
@interface BlockValueVC : UIViewController
@property (nonatomic, strong) void(^block)(NSString *value);
@end
//在BlockValueVC.m文件中使用
#import "BlockValueVC.h"
@interface BlockValueVC ()
@end
@implementation BlockValueVC
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// 传值给ViewController
// @"123"
//判断是否存在 调用Block
if (_block) {
_block(@"123");
}
}
//打印结果
传值结果: 123
block循环引用
#import "ViewController.h"
#import "VC.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor redColor];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
VC *vc = [[VC alloc] init];
[self presentViewController:vc animated:YES completion:nil];
}
@end
**************************VC控制器**************************
#import "VC.h"
@interface VC ()
@property (nonatomic, strong) void(^block)(void);
@end
@implementation VC
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor purpleColor];
_block = ^{
NSLog(@"看看对象:%@",self);
};
_block();
}
- (void)dealloc {
NSLog(@"控制器是否销毁");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self dismissViewControllerAnimated:YES completion:nil];
}
//打印结果
017-10-09 11:43:23.300091+0800 04-Block的循环引用[3404:119114] 看看对象:<VC: 0x7fdcaf524040>
//控制器并没有销毁
//原因:下图
block循环图.png
解决方法
// block造成循环利用:Block会对里面所有强指针变量都强引用一次
// __weak typeof(self) weakSelf = self;
//我们在VC控制器里面的viewDidLoad方法中进行修改
- (void)viewDidLoad {
[super viewDidLoad];
__weak typeof(self) weakSelf = self;
_block = ^{
NSLog(@"%@",weakSelf);
};
_block();
}
//打印结果
017-10-09 11:43:23.300091+0800 04-Block的循环引用[3404:119114] 看看对象:<VC: 0x7fdcaf524040>
017-10-09 11:43:23.300091+0800 04-Block的循环引用[3404:119114] 控制器是否销毁
//注意:如果在block中在使用block需要是使用 __strong typeof(weakSelf) strongSelf = weakSelf;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
// block造成循环利用:Block会对里面所有强指针变量都强引用一次
__weak typeof(self) weakSelf = self;
_block = ^{
//防止循环引用
NSLog(@"%@",weakSelf);
//防止_block内部的block在访问weakSelf对象的时候销毁
__strong typeof(weakSelf) strongSelf = weakSelf;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@",strongSelf);
});
};
//调用block
_block();
}
block作为参数使用
//这样的使用方式很多,比如AFN网络请求时
//后续补上
网友评论