block
其实Block就是一个对象,可以理解为这个对象保存了我们写到括号里面的方法函数的地址的指针,当我们调用这个Block的时候就是调用了括号里面的方法,并且调用block时传入的参数就相当于就传给了括号里面需要的参数。
block作为传入参数的一个函数
-(void)calculate:(int(^)(int))calculateBlock;
- 调用了这个函数方法,就相当于我们把括号里写的方法,看做一个整体被打包了,等待着被调用唤醒,也可以直接去唤醒
[manager calculate:^int(int i) {
i++;
NSLog(@"调用");
return i;
}];
复制代码
- 这里直接就calculateBlock() 把结果给了result.
-(void)calculate:(int (^)(int))calculateBlock
{
//calculateBlock接受外界传入的代码块,也就意味着怎么去操作是由外界调用者决定的
_result = calculateBlock(_result);//将_result的值作为实参传入
}
复制代码
block 起别名 就是为了方便书写。
typedef int (^TestBlock)(int); 传入int返回int的block
typedef NSString *_Nonnull(^KKBlock)(int); 传入int返回String的Block
- 设置属性
@property(nonatomic,copy)TestBlock testBlock;
@property(nonatomic,copy)KKBlock testKKBlock;
需求
- 现在有个需求就是我点击屏幕数字Int就会持续加1,但是我现在就想知道 这个值+100后是双数还是单数
- 用Block 来完成
先放源码
- CalculatorManager.h
#import <Foundation/Foundation.h>
typedef int (^TestBlock)(int);
typedef NSString *_Nonnull(^KKBlock)(int);
NS_ASSUME_NONNULL_BEGIN
@interface CalculatorManager : NSObject
/** 计算结果值*/
@property(assign, nonatomic) int result;
/** 结果值1字符串*/
@property(copy, nonatomic) NSString *resultStr;
/** 结果值2字符串*/
@property(copy, nonatomic) NSString *resultStr2;
/** 这个Block 暴露出去 不使用函数方法进行设置*/
@property(nonatomic,copy)KKBlock test2KKBlock;
@property(assign, nonatomic) int x;
+(instancetype)sharedCalculatorManager;
//block作为参数时格式与其它类型定义时一致,都是(类型)变量名,看起来有些晕人
-(void)calculate:(int(^)(int))calculateBlock;
//通过函数的方法给int型的block赋值
-(void)calculate1:(TestBlock)Block;
//通过函数的方法给字符串型的block赋值
-(void)calculate2:(KKBlock)Block;
@end
NS_ASSUME_NONNULL_END
复制代码
- CalculatorManager.m
#import "CalculatorManager.h"
static CalculatorManager *instance = nil;
@interface CalculatorManager ()
@property(nonatomic,copy)TestBlock testBlock;
@property(nonatomic,copy)KKBlock testKKBlock;
@end
@implementation CalculatorManager
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (instance == nil) {
instance = [super allocWithZone:zone];
}
});
return instance;
}
+(instancetype)sharedCalculatorManager
{
return [[self alloc] init];
}
//方法中定义了一个block数据类型参数(返回值为int类型的,且带有一个int类型的形参)
-(void)calculate:(int (^)(int))calculateBlock
{
//calculateBlock接受外界传入的代码块,也就意味着怎么去操作是由外界调用者决定的
_result = calculateBlock(_result);//将_result的值作为实参传入
}
// 通过函数方法给block赋值,相当于调用 calculate1 时 写到括号里面的代码给打包保存起来了放到了上面的属性中,等待着被调用。
-(void)calculate1:(TestBlock)Block{
self.testBlock = Block;
}
//同上
-(void)calculate2:(KKBlock)Block{
self.testKKBlock = Block;
}
//暴露给外面的X set方法,当x被赋值的时候回触发这些block,就是说一旦给这个X赋值,就开始调用括号里面的方法了,有返回值的就分别保存到了 reslutStr 中。
- (void)setX:(int)x{
_x = x;
_result = self.testBlock(x);
if (_testBlock) {
self.resultStr = _testKKBlock(x);
}
if (_testKKBlock) {
self.resultStr2 = _test2KKBlock(x);
}
}
@end
复制代码
- viewController
#import "ViewController.h"
#import "CalculatorManager.h"
@interface ViewController ()
{
int A;
NSString *_restult3;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
CalculatorManager *manager = [CalculatorManager sharedCalculatorManager];
// [manager calculate:^int(int i) {
// i++;
// NSLog(@"调用");
// return i;
// }];
// NSLog(@"%d",manager.result);
__weak typeof(self) weakSelf = self;
[manager calculate1:^int(int x) {
NSLog(@"%d",manager.x);
return x+100;
}];
[manager calculate2:^NSString * _Nonnull(int x) {
if (x % 2 == 1) {
return @"单数";
}else{
return @"双数";
}
}];
manager.test2KKBlock = ^NSString * _Nonnull(int x) {
__strong typeof(self) strongSelf = weakSelf;
return [strongSelf getTheStringWithInt:x];
};
}
- (NSString *)getTheStringWithInt:(int)x{
NSString *resultStr = [NSString stringWithFormat:@"处理结果是%d",x];
return resultStr;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
A++;
CalculatorManager *manager = [CalculatorManager sharedCalculatorManager];
manager.x = A;
NSLog(@"%d",manager.result);
NSLog(@"%@",manager.resultStr);
NSLog(@"%@",manager.resultStr2);
}
@end
复制代码
- 控制器里面就很简单了,点击触发X的赋值,X就一直++,就会触发上面写的Block里面的函数,记录返回值,答应。
- 所以说把Block看成普通的NSString 这些之后其实没那么可怕就是可能写的形式有点复杂。然后呢就是很多的第三方通常都是把block作为参数传入的,造成可读性不强,不太容易理解。
Block作为参数使用,常见于各框架之中,比如在封装一个类时,当做什么事情由外界去决定,什么时候调用由自己的类决定时,这时候就需要将block作为参数使用。
- 做什么事情由外界去决定,在外部给这个block写方法,像我例子中的test2KKBlock,做的什么事情其实就是外部决定的
getTheStringWithInt
这个函数 - 什么时候调用由自己类决定,这个决定就是我自己的
X
发生改变时我自己来调用。你这个具体的做法就放在那里等待我去调用。
- 上面的文章大家看看就过吧,忘得差不多了哈哈哈哈。
- 自我思考
- 是不是 函数可以作为函数的参数传入呢。swift好像有这么写的吧。
- 但是好像没有看见过用block作为函数的返回值的哦。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END