block备忘录
前言
随著block
在iOS4.0和OS X 10.6的引入,给事件传递一种新的方式实现,在开发中用得最多的场景莫过于事件回调。使用block
相对与delegate
的优势在于,业务集中,可读性强,代码内联,不像代理需要实现很多函数,在适当的场景选择这种方式实现事件传递或者传参效果非常好,现在很多开源项目都实现了两种方法的事件回调。
block
用起来虽然很爽,但也有它的不足,存在循环引用,轻者内存泄露,甚至导致App崩溃,不易调试追溯,因此使用它使一定要小心。鉴于实践中的踩过各种坑,总结下来,方便自己和他人以后查阅,这就是block备忘录写作的初衷。
block的本质
block
实际上是指向结构体的指针,编译时,block
的内部代码生产对应的函数。
具体结构如下:
block结构图与C语言的函数指针的区别
-
block
的代码是内联的,效率高于函数调用 -
block
对于外部变量默认是只读属性 -
block
被Objective-C
看成是对象处理
block声明
-
作为
property
@property (nonatomic, copy) returnType (^blockName)(parameterTypes);
-
作为方法参数
- (void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName;
-
作为一个方法调用参数
[someObject someMethodThatTakesABlock:^returnType (parameters) {...}];
-
作为一个
typedef
typedef returnType (^TypeName)(parameterTypes);
TypeName blockName = ^returnType(parameters) {...};
-
作为函数参数
int (^sumOfNumbers)(int a, int b) = ^(int a, int b) {
return a + b;
};
SDWebImage
中使用的block
示例:
typedef void(^SDWebImageCompletionBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL);
typedef void(^SDWebImageCompletionWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL);
typedef NSString *(^SDWebImageCacheKeyFilterBlock)(NSURL *url);
block调用
跟C函数类似使用()
,括号里面还可以带一个或者多个参数
// block声明
(void)(^loggerBlock)(void);
// block定义
loggerBlock = ^{
NSLog("hello world")
};
// block调用
loggerBlock();
block内存管理
默认情况下,block
是在栈内存中,它不会对所引用的对象进行任何操作;如果对block
进行一次copy
操作,block
就会在堆内存中,并且它会它所有的引用的对象做一次retain
操作
- 对于block外的变量引用,block 默认是将其复制到其数据结构中来实现访问的
- 对于用
__block
修饰的外部变量引用,block 是复制其引用地址来实现访问的 - 而block会捕获代码外的局部变量,并且仅限于只读操作
- 在block中希望修改的外界局部对象,必须加上
__block
关键词
ARC
如果对象使用`__unsafe_unretained`或`__weak`修饰,就不会对其做`retain`操作
MRC
如果对象使用了`__block`修饰, 就不会对其做`retain`操作
为了防止block
中的循环引用,可以用__weak
关键词把相应的对象声明为弱引用,在block
快内部需要多次访问,防止该对象被释放,可以用__strong
关键词将声明为强引用:
__weak __typeof__(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
__strong __typeof(self) strongSelf = weakSelf;
[strongSelf doSomething];
[strongSelf doOtherThing];
});
原文发表于王若风的技术博客