这是我参与「第四届青训营」笔记创作活动的的第4天
1 闭包基础
闭包本身是一个结构体,存储了函数入口地址和与之绑定的一系列环境,环境里面既有其本身内部定义的变量,又包含从外部捕获的变量,捕获变量的处理因实现而异。
2 Block基础
2.1 简单例子
// block声明
returnType (^blockName)(parameters);
// block赋值
^returnType(parameters) {
// do something;
};
// 示例
int (^sumBlock)(int a, int b) = ^int(int a, int b) {
return a + b;
};
int sum = sumBlock(1, 1);
省略写法
// 有返回值有入参
int (^sumBlock)(int, int) = ^(int a, int b) {
return a + b;
};
// 无返回值无入参
void (^printBlock)(void) = ^{
NSLog(@"Hello World!");
};
3 Block内存管理
ARC机制,在一些默认的情况下系统会帮你自动调用copy操作:
- block作为函数返回值
- 将block赋值给strong指针
- block作为某些系统方法参数
3.1 变量捕获
3.1.1 值捕获
- (void)changeValue {
int value = 1;
void (^oneBlock)(void) = ^{
NSLog(@"value = %d", value); // value1:1
};
value = 2;
oneBlock();
NSLog(@"value = %d", value); // value2:2
NSString *value = @"1";
void (^oneBlock)(void) = ^{
NSLog(@"value = %@", value); // value1:1
}
value = @"2";
oneBlock();
NSLog(@"value = %@", value); // value2:2
}
由于oneBlock在初始化的时候,按值捕获了value,而后,当value更改后,block内捕获的值并没有跟着一起变化;而value2处则是使用的改变后的变量。
3.1.2 引用捕获
- (void)changeValue {
__block int value = 1;
void (^oneBlock)(void) = ^{
NSLog(@"value = %d", value); // value1:2
value = 3;
};
value = 2;
oneBlock();
NSLog(@"value = %d", value); // value2:3
}
@property (nonatomic, copy) NSString *name;
- (void)changeValue {
self.name = @"1";
void (^oneBlock)(void) = ^{
NSLog(@"value = %@", self.name); // value1:2
}
self.name = @"2";
oneBlock();
NSLog(@"value = %@", self.name); // value2:2
}
想要修改传入的值并生效:
上面的代码块和之前的很像,区别在于传入的变量前增加了一个关键字__block
,这个关键字标志了该变量允许在block中被修改,这里block内部对于value的捕获是引用捕获,也就是说block中的value就是外部的value对象,因此对应值的改变也会同步,内外互相影响
3.2 Block的循环引用
在ARC下,系统会在某些场景默认对block执行copy操作,使其变为__NSMallocBlock__,此时block也会有自己的内存引用计数。
简单例子
// ViewController.m
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) void (^completionBlock)(void);
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.completionBlock = ^{
NSLog(@"%@", self.name);
};
}
@end
解决方法
__weak typeof(self) weakSelf = self;
self.completionBlock = ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
NSLog(@"%@", strongSelf.name);
};
4 Block的应用
4.1 网络请求中数据传递
// AFHTTPSessionManager.h
- (nullable NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(nullable id)parameters
progress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
网络请求传入url、网络参数以及进度、成功和失败的回调block,这三个block就是主要负责数据传递的
AFHTTPSessionManager *manager = AFHTTPSessionManager.manager;
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"image/jpeg", nil];
__weak typeof(self) weakSelf = self;
NSString *url = @"<http://www.pptbz.com/pptpic/UploadFiles_6909/201203/2012031220134655.jpg>";
// 开始下载
[manager GET:url parameters:nil progress:^(NSProgress *downloadProgress) {
NSLog(@"progress:%lld",downloadProgress.completedUnitCount);
} success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"图片下载完成");
__strong typeof(weakSelf) strongSelf = weakSelf;
strongSelf.imgView.image = [UIImage imageWithData:(NSData *)responseObject];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
if (error) {
NSLog(@"%@",error.userInfo);
}
}];
5 小结
本节课学习了在OC里面重要的Block,对Block的基础知识,基础应用有了一个简单了解,Block在开发过程中对数据的传递起到了重要作用