swift 里面的 defer 可真是太好用,可是 OC 有时候也是不得不用的,写就写吧,可是当我需要 defer 的时候 OC 却没有,这总让人有些不得劲儿
比如下面这样
uint8_t *cmpResult = malloc(capacity); // 申请内存
int cmpCode = someCFunction(cmpResult) // 调用 C 函数
if (cmpCode != 0) {
free(cmpResult); // 释放内存
return nil;
}
if (...) {
free(cmpResult); // 释放内存
return nil;
}
NSData *resultData = [NSData dataWithBytes:cmpResult length:cmpImageSize];
free(cmpResult); // 释放内存
return resultData;
这要求我们写代码必须要仔细认真,在申请完内存后处理好流程中的每一处分支,每一处分支都必须 有且仅有 有且仅有 有且仅有 一次调用 free(cmpResult); 来释放内存
幸运的是,OC 还真有办法,能实现 defer 功能,上面的代码就可以简化得清晰明了
__block uint8_t *cmpResult = malloc(capacity); // 申请内存
@defer {
// 紧跟着申请完的内存,马上在 defer 里面释放
free(cmpResult);
};
// 后面完全不考虑内存释放的事情
// 把后面的所有的 free(cmpResult); 都删掉
实现方法呢,来自于这篇文章 《 如何在 Objective-C 的环境下实现 defer 》,原理和细节里面也讲得很清楚,我就不像复读机一样制造垃圾了
这里提供一下我实现 defer 的代码,放在一个 .h 头文件里就可以用了
// GG_defer.h
#ifndef GG_defer_h
#define GG_defer_h
#define gg_concat(A, B) gg_concat_(A, B)
#define gg_concat_(A, B) A ## B
#define defer \
autoreleasepool {} \
__strong ext_cleanupBlock_t gg_concat(ext_exitBlock_, __LINE__) __attribute__((cleanup(ext_executeCleanupBlock), unused)) = ^
typedef void (^ext_cleanupBlock_t)(void);
void ext_executeCleanupBlock (__strong ext_cleanupBlock_t *block) {
(*block)();
}
#endif /* defer_h */