Block
参数传值的一般方式:
顺传:给需要传值的对象直接定义属性就能传值
逆传:用代理(delegate),Block
Block声明
返回值(^block变量名)(参数)
Block定义
- void(^block)() = ^(){...}; 如果有参数,必须要写参数 void(^block)(int) = ^(int a){...};
- void(^block)() = ^{...}; 如果没有参数,参数可以隐藏
- int(^block)() = ^int{...}; block返回值可以省略,不管有没有返回值,都可以省略
Block类型
int(^block)(NSString*) = ^(NSString *name){return @"Hello"};
Block调用
int(^block)(NSString*) = ^(NSString *name){return @"Hello"};
block();//调用
Block快捷方式
//敲inlineBlock后,就会自动生成代码:
<#returnType#>(^<#blockName#>)(<#parameterTypes#>) = ^(<#parameters#>) {
<#statements#>
};
Block使用场景
1.在一个方法中定义,在另一个方法中调用
2.在一个类中定义,在另一个类中调用
Block的几种用法
用法一:
//不带参数
void(^block1)() = ^(){
NSLog(@"正在执行block1");
};
block1();
//带参数
void(^block2)(int a,int b) = ^(int a,int b){
NSLog(@"正在执行block2");
int c = a + b;
NSLog(@"a + b = %d",c);
};
block2(3,9);
用法二:
#import "ViewController.h"
typedef void(^MyBlock)();
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
MyBlock block1 = ^{
NSLog(@"正在执行block1");
};
block1();
}
@end
用法三(跨越方法调用):
#import "ViewController.h"
typedef void(^MyBlock)();
@interface ViewController ()
@property(copy,nonatomic)MyBlock block2;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.block2 = ^{
NSLog(@"正在执行block2");
};
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.block2();
}
@end
用法四(跨越方法调用):
#import "ViewController.h"
@interface ViewController ()
@property (strong, nonatomic) void(^block)();
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.block = ^{
NSLog(@"调用了Block");
};
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.block();
}
@end
用法五(跨越类的调用):
BlockClass.h
#import <Foundation/Foundation.h>
@interface BlockClass : NSObject
@property (strong, nonatomic) void(^block)();
@end
ViewController.m
#import "ViewController.h"
#import "BlockClass.h"
@interface ViewController ()
@property (strong,nonatomic)BlockClass *blockClass1;
@property (strong,nonatomic)BlockClass *blockClass2;
@property (strong,nonatomic)BlockClass *blockClass3;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.blockClass1 = [[BlockClass alloc]init];
self.blockClass2 = [[BlockClass alloc]init];
self.blockClass3 = [[BlockClass alloc]init];
self.blockClass1.block = ^{
NSLog(@"圣诞快乐");
};
self.blockClass2.block = ^{
NSLog(@"元旦快乐");
};
self.blockClass3.block = ^{
NSLog(@"春节快乐");
};
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.blockClass1.block();
self.blockClass2.block();
self.blockClass3.block();
}
@end
用法六(值的逆传):
BlockClass.h
#import <Foundation/Foundation.h>
@interface BlockClass : NSObject
@property (strong, nonatomic) void(^paramBlock)(int value);
@end
BlockClass.m
#import "BlockClass.h"
@implementation BlockClass
- (instancetype)init
{
if(self = [super init])
{
//每隔1秒执行一次block
[NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
if(self.paramBlock)
{
int value = 123;
self.paramBlock(value);
}
}];
}
return self;
}
@end
ViewController.m
#import "ViewController.h"
#import "BlockClass.h"
@interface ViewController ()
@property (strong,nonatomic)BlockClass *blockClass;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.blockClass = [[BlockClass alloc]init];
self.blockClass4.paramBlock = ^(int value){
//设置代码块功能
NSLog(@"%d",value);
};
}
@end
输出:(每隔1秒输出一次)
2016-12-25 23:43:32.151 BlockTest2[11235:346225] 123
2016-12-25 23:43:33.151 BlockTest2[11235:346225] 123
2016-12-25 23:43:34.213 BlockTest2[11235:346225] 123
2016-12-25 23:43:35.176 BlockTest2[11235:346225] 123
Block内存管理
block对象一般存在于堆、栈或全局区
MRC:
- 只要block没有一用外部局部变量,block放在全局区
void(^block)() = ^{
NSLog(@"调用Block");
};
/*<__NSGlobalBlock__: 0x10de380d0> block放在全局区*/
NSLog(@"%@",block);
- 当block引用了外部局部变量,则会放在栈里面
__block int a = 3;
void(^block)() = ^{
NSLog(@"调用Block%d",a);
};
/*<__NSStackBlock__: 0x7fff52052950>放在栈*/
NSLog(@"%@",block);
定义一个全局属性方法
@property(copy,nonatomic) void(^block)();//MRC下没有strong,weak
只能使用copy,如果使用retain修饰,block还在栈中,会被销毁
ARC:
只要block引用了外部局部变量,则会放在堆里
__block int a = 3;
void(^block)() = ^{
NSLog(@"调用Block%d",a);
};
/*<__NSMallocBlock__: 0x600000054e80>放在堆*/
NSLog(@"%@",block);
定义一个全局属性方法
@property(strong,nonatomic) void(^block)();
使用strong修饰,如果使用weak修饰,会被销毁,如果不考虑防止值的改变,也尽量不要用copy
Block的循环引用
循环引用:两个对象互相引用
@interface BlockClass : NSObject
@property (strong, nonatomic) void(^block)();
@end
@implementation BlockClass
- (instancetype)init
{
if(self = [super init])
{
self.block = ^{
NSLog(@"%@",self);//警告:Capturing 'self' strongly in this block is likely to lead to a retain cycle,这样的情况就是循环引用
};
}
return self;
}
@end
解决的办法
//要定义一个弱引用指向self
__weak typeof(self) weakSelf = self;
self.block = ^{
NSLog(@"%@",weakSelf);
};
如果block中有延时操作,延时以后还需要用到self,还需这样:
//先定义一个弱引用指向self
__weak typeof(self) weakSelf = self;
//再定义一个强引用指向weakSelf
self.block = ^{
__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中是值传递
- (void)viewDidLoad{
int a = 3;
void(^block)() = ^{
NSLog(@"%d",a);//输出3
};
a = 5;
block();
}
如果是静态变量,在block中是指针传递
- (void)viewDidLoad{
static int a = 3;
void(^block)() = ^{
NSLog(@"%d",a);//输出5
};
a = 5;
block();
}
如果是全局变量,在block中是指针传递
int a = 3;
- (void)viewDidLoad{
void(^block)() = ^{
NSLog(@"%d",a);//输出5
};
a = 5;
block();
}
如果是__block修饰,在block中是指针传递
__block int a = 3;
- (void)viewDidLoad{
void(^block)() = ^{
NSLog(@"%d",a);//输出5
};
a = 5;
block();
}
Block作为方法的参数
CacultorManager.h
@interface CacultorManager:NSObject
@property (nonatomic, assign) NSInteger result;
// 计算
- (void)cacultor:(NSInteger(^)(NSInteger result))cacultorBlock;
@end
CacultorManager.m
@implementation CacultorManager
- (void)cacultor:(NSInteger (^)(NSInteger))cacultorBlock
{
if (cacultorBlock) {
_result = cacultorBlock(_result);
}
}
@end
ViewController.m
...
- (void)viewDidLoad {
[super viewDidLoad];
[self test:3];
// 创建计算器管理者
CacultorManager *mgr = [[CacultorManager alloc] init];
[mgr cacultor:^(NSInteger result){
result += 5;
result += 6;
result *= 2;
return result;
}];
NSLog(@"%ld",mgr.result);
}
...
Block当做返回值
- (void)viewDidLoad
{
self.test();//只有返回值为block的方法才会这样调用
//上面写法相当于:
//void(^block)() = [self test];
//block();
}
-(void(^)())test
{
return ^{
NSLog(@"调用了block");
};
}
使用Block返回值实现的链式编程思想
#import <Foundation/Foundation.h>
@interface CalculatorManager : NSObject
@property (nonatomic, assign) int result;
- (CalculatorManager *(^)(int))add;
//使用方法实现
//- (CalculatorManager *)add:(int)value;
@end
CalculatorManager.m
#import "CalculatorManager.h"
@implementation CalculatorManager
- (CalculatorManager *(^)(int))add
{
return ^(int value){
_result += value;
return self;
};
}
//使用方法实现
//- (CalculatorManager *)add:(int)value
//{
//_result += value;
//
//return self;
//}
ViewController.m
...
- (void)viewDidLoad {
[super viewDidLoad];
CalculatorManager *mgr = [[CalculatorManager alloc] init];
mgr.add(5).add(5).add(5).add(5);
//使用方法实现,虽然实现,但写法不太美观
//[[[[[mgr add:5] add:5] add:5] add:6] add:7];
NSLog(@"%d",mgr.result);
...