- block作用:保存一段代码
1.block声明
2.block定义
4.block类型
5.block调用
//block的声明 返回值 (^block的名字)(参数)
void (^myblock)();
/*定义 = ^(参数){} */
//1.没有参数, 没有返回值
void (^block1)() = ^{ //没有参数在定义的时候可以省略
NSLog(@"调用了block1");
};
// 2 如果没有参数,参数可以隐藏,如果有参数,定义的时候,必须要写参数,而且必须要有参数变量名
void (^block2) (int) = ^(int a) //有参数 没有返回值的
{
};
//3 第三种 block返回可以省略,不管有没有返回值,都可以省略
int (^block3)() = ^int
{
return 3;
};
int (^block4)() = ^
{
return 4;
};
//block的调用
block1();
// block快捷方式 inline
// <#returnType#>(^<#blockName#>)(<#parameterTypes#>) = ^(<#parameters#>) {
// <#statements#>
// };
开发中的使用场景
-
1保存代码
- 在一个方法中定义在另一个方法中调用
//定义别名
typedef void(^BlockTyoe)();
@interface ViewController ()
@property (nonatomic, strong) BlockTyoe block1;
@property (nonatomic, strong) void(^block)();
// 1.在一个方法中定义,在另外一个方法调用
// 2.在一个类中定义,在另外一个类中调用
/*
1.tableView展示3个cell,打电话,发短信,发邮件
*/
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
void (^block) () = ^
{
NSLog(@"在这里保存了一份需要执行的代码");
};
_block = block;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
self.block();//执行
// UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[[MyToolTVC alloc]init]];
// [self presentViewController:nav animated:YES completion:nil];
}
- (void)viewDidLoad {
[super viewDidLoad];
_items = [NSMutableArray array];
MyToolItem *item1 = [MyToolItem itemWithTitle:@"打电话"];
item1.clickAciton = ^
{
NSLog(@"我要打电话");
};
[self.items addObject:item1];
MyToolItem *item2 = [MyToolItem itemWithTitle:@"发短信"];
item2.clickAciton = ^
{
NSLog(@"我要打短信");
};
[self.items addObject:item2];
MyToolItem *item3 = [MyToolItem itemWithTitle:@"发邮件"];
item3.clickAciton = ^
{
NSLog(@"我要邮件");
};
[self.items addObject:item3];
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.items.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *const toolCellId = @"toolCellId";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:toolCellId ];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:toolCellId];
}
MyToolItem *item = self.items[indexPath.row] ;
cell.textLabel.text = item.toolTitle;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
MyToolItem *item = self.items[indexPath.row] ;
item.clickAciton();
}
-
2传值
- 传值:1.只要能拿到对方就能传值
顺传:给需要传值的对象,直接定义属性就能传值
逆传:用代理,block,就是利用block去代替代理
- 传值:1.只要能拿到对方就能传值
代理传值
#import "ViewController.h"
#import "ModelViewViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
/*
传值:1.只要能拿到对方就能传值
顺传:给需要传值的对象,直接定义属性就能传值
逆传:用代理,block,就是利用block去代替代理
*/
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
ModelViewViewController *modelVC = [[ModelViewViewController alloc] init];
modelVC.delegate = self;
modelVC.view.backgroundColor = [UIColor orangeColor];
[self presentViewController:modelVC animated:YES completion:nil];
}
- (void)modelViewController:(ModelViewViewController *)vc senderMessage:(NSString *)message
{
NSLog(@"收到了消息%@", message);
}
@end
@class ModelViewViewController;
@protocol ModelViewControllerDelegate
- (void)modelViewController:(ModelViewViewController *)vc senderMessage:(NSString *)message;
@end
@interface ModelViewViewController : UIViewController
@property (nonatomic, weak) id delegate;
@end
#import "ModelViewViewController.h"
@interface ModelViewViewController ()
@end
@implementation ModelViewViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.delegate && [self.delegate respondsToSelector:@selector(modelViewController:senderMessage:)]) {
[self.delegate modelViewController:self senderMessage:@"12355"];
}
}
@end
- block传值
@interface ModelViewViewController : UIViewController
@property (nonatomic, weak) id delegate;
@property (nonatomic, strong) void(^sendValue)(NSString *);
@end
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.sendValue) {
self.sendValue(@"你好呀 block");
}
}
/*********ViewController.m*******/
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
ModelViewViewController *modelVC = [[ModelViewViewController alloc] init];
modelVC.sendValue =^ (NSString *value)
{
NSLog(@"这是收到的%@", value);
};
modelVC.view.backgroundColor = [UIColor orangeColor];
[self presentViewController:modelVC animated:YES completion:nil];
}
block的内存管理
-
mrc
block是不是一个对象?是一个对象
如何判断当前文件是MRC,还是ARC
1.dealloc 能否调用super,只有MRC才能调用super
2.能否使用retain,release.如果能用就是MRC
ARC管理原则:只要一个对象没有被强指针修饰就会被销毁,默认局部变量对象都是强指针,存放到堆里面
MRC了解开发常识:1.MRC没有strong,weak,局部变量对象就是相当于基本数据类型
2.MRC给成员属性赋值,一定要使用set方法,不能直接访问下划线成员属性赋值
MRC:管理block
总结:只要block没有引用外部局部变量,block放在全局区
只要Block引用外部局部变量,block放在栈里面.
block只能使用copy,不能使用retain,使用retain,block还是在栈里面-
ARC:管理block
只要block引用外部局部变量,block放在堆里面
block使用strong.最好不要使用copy
@property (nonatomic, strong) void(^block) ();
@end
/*
ARC:管理block
只要block引用外部局部变量,block放在堆里面
block使用strong.最好不要使用copy
*/
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
__block int a = 3;
void(^block)()= ^
{
NSLog(@"%d",3);
a = 4;
};
self.block = block;
}
block的循环引用
- 循环引用:我引用你,你也引用,就会造成循环引用,双方都不会被销毁,导致内存泄露问题
- block造成循环利用:Block会对里面所有强指针变量都强引用一次
比如我们如果在block中直接引用self当控制器被diss Miss的时候我们发现 并没有执行销毁,这就出现了循环了引用,因为block会对当前的控制器进行强引用,解决方法,定义一个弱引用,
NSLog(@"%@", self);
__weak typeof (self) weakSelf = self;
self.block= ^
{
NSLog(@"%d", weakSelf.age);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// NSLog(@"引用了%@", strongSelf);
});
};
self.block();
}
- 弱引用可以实现我们的平时开发所用到的基本的功能,如果我们想在延迟的时候使用的话需要对weakself强引用一次防止他被销毁
这样我们就要对他进行一次引用
__weak typeof (self) weakSelf = self;
self.block= ^
{
NSLog(@"%d", weakSelf.age);//如果block里面有延迟操作,可能你会照成 拿不到当前的控制器,比如 被dismiss掉了
//如果我们想在延迟的时候使用的话需要对weakself强引用一次防止x他被销毁
__strong typeof(weakSelf) strongSelf = weakSelf;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//延迟执行的时候 被modal出的控制应景dismiss掉了,但是不会执行销毁
NSLog(@"引用了%@", strongSelf);
});
};
self.block();
- 原理
viewController 通过present出modalController,这时候 viewController会有一个强指针,指向modal,然后block中有定义一个 __strong typeof(weakSelf) strongSelf = weakSelf;
这样block也有一个强指针指向了modal控制器,然后延迟的block中引用了strongSelf这样就对strongSelf这个局部变量有了强引用。保证了让他不销毁。当我们在执行dismiss的时候viewController指向modal的强指针去掉了, 当执行了延迟操作之后,系统会将这个延迟操作中的block中引用的强去掉指针。当延迟的操作的强指针去掉后,上一个block中的strongSelf就没有强指针引用了,所以也会被系统销毁。这样就没有强指针指向当前的modal对象了,这个时候他才会被系统销毁。
block变量传递
- 如果是局部变量,Block是值传递
如果是静态变量,全局变量,__block修饰的变量,block都是指针传递
- (void)viewDidLoad {
[super viewDidLoad];
int a = 3;
self.block = ^
{
NSLog(@"%d", a);//3
};
a= 5;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
self.block();
}
block当参数使用
- 怎么区分参数是block,就看有没有,只要有.把block当做参数
把block当做参数,并不是马上就调用Block,什么时候调用,由方法内部决定。
什么时候需要把block当做参数去使用:做的事情由外界决定,但是什么时候做由内部决定.
CaculterViewController *cacultorVC = [[CaculterViewController alloc] init];
[cacultorVC cacultor:^NSInteger(NSInteger result) {
result +=2;
result +=6;
result *= 3;
return result;
}];
NSLog(@"%ld", cacultorVC.result);
/ *******************/
#import "CaculterViewController.h"
@interface CaculterViewController ()
@end
@implementation CaculterViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)cacultor:(NSInteger (^)(NSInteger))cacultorBlock
{
if (cacultorBlock) {
_result = cacultorBlock(_result);
}
}
作为返回值
- 链式编程思想:把所有的语句用.号连接起来,好处:可读性非常好
当方法的返回值为block类型的时候,可以用.语法加()直接调用,最常见的就是masonry,d我们定约束的时候全部都使用的.
make.center .equalTo(redView)
#import "ViewController.h"
#import "CaculterViewController.h"
@interface ViewController ()
@end
@implementation ViewController
/*
需求:封装一个计算器,提供一个加号方法
*/
- (void)viewDidLoad {
[super viewDidLoad];
self.test();
//上面的方法相当于
void (^testB)() = self.test;
testB();
//当函数的返回值为block的时候可以用();就好比直接调用block,
^{
NSLog(@"myanmetest");
}();
CaculterViewController *mgr = [[CaculterViewController alloc] init];
mgr.add(3).add(5).add(8);
NSLog(@"%d", mgr.result);
}
- (void (^)())test
{
return ^{
NSLog(@"调用返回的block");
};
}
/***************************/
- (CaculterViewController * _Nonnull (^)(NSInteger))add
{
return ^(NSInteger value){
_result += value;
return self;
};
}