defer
defer
是Swift中比较常用的一种语法,defer
中的代码将会在当前的代码块结束之后调用。正如文档中所说:
You use a defer statement to execute a set of statements just before code execution leaves the current block of code. This statement lets you do any necessary cleanup that should be performed regardless of how execution leaves the current block of code—whether it leaves because an error was thrown or because of a statement such as return or break.
无论你的代码块是通过break退出还是return退出,你在defer中代码都会得到执行,简单演示如下:
func processFile(filename: String) throws {
if exists(filename) {
let file = open(filename)
defer {
close(file)
}
while let line = try file.readline() {
// Work with the file.
}
// close(file) is called here, at the end of the scope.
}
}
cleanup
OC中也有类似的概念,那就是黑魔法之一 __attribute__(cleanup(...))
。
cleanup用来修饰一个变量,当他的作用域结束,一般来讲就是当前的代码块执行结束的时候,可以执行一个指定的方法。当然,这个变量也可以是一个block。
__unused static void cleanUpBlock(__strong void(^*block)(void)) {
(*block)();
}
- (void)cleanUp {
__strong void(^attribute_cleanup_block)(void) __attribute__((cleanup(cleanUpBlock), unused)) = ^{
NSLog(@"clean up");
};
NSLog(@"processing");
}
当然我们也可以把上面的内容变成一个宏方便我们使用:
#ifdef __GNUC__
__unused static void cleanUpBlock(__strong void(^*block)(void)) {
(*block)();
}
#define OnBlockExit __strong void(^attribute_cleanup_block)(void) __attribute__((cleanup(cleanUpBlock), unused)) = ^
#endif
- (void)cleanUp {
OnBlockExit{
NSLog(@"Clean up");
};
NSLog(@"processing");
}
复数场景
还有一点要说的就是 Swift中的defer是可以叠加的,也就是说我也以写出如下的代码:
func cleanup() {
defer {
print("defer 1")
}
defer {
print("defer 2")
}
defer {
print("defer 3")
}
print("End")
}
cleanup()
控制台会依次输出:
End
defer 3
defer 2
defer 1
OC中由于上面的宏定义的block名称相同,所以简单对宏做了一点改动,将block的名称摘了出来:
#define OnBlockExit(block_name) __strong void(^block_name)(void) __attribute__((cleanup(cleanUpBlock), unused)) = ^
- (void)cleanUp {
OnBlockExit(block_1) {
NSLog(@"OnBlockExit 1");
};
OnBlockExit(block_2) {
NSLog(@"OnBlockExit 2");
};
OnBlockExit(block_3) {
NSLog(@"OnBlockExit 3");
};
NSLog(@"End");
}
//控制台输出:
End
OnBlockExit 3
OnBlockExit 2
OnBlockExit 1
可以看出无论是 defer还是cleanup,再添加“死亡回调”的时候都是按照栈的结构添加的。
应用
defer常用与需要配对出现的代码,比如文件的打开与关闭,加锁与解锁,ARC以外的对象,如CoreGraphics中对象的create与release等。
由于代码较少,且网上也可以搜到很多类似的资料,这次就不提供源码了,谢谢大家支持 : )