个人博客的云服务器不打算续费了,所以会陆续将上面的一些文章迁移到这里来,格式可能不兼容,见谅。
attribute
编译器属性__attribute__
用于向编译器描述特殊的标识、检查或优化,几个常用的用法看这篇文章就好。
cleanup
理解代码先从命名开始,cleanup
中文意为"清理",那么可以知道这个关键字执行的应该和清理操作相关。
实际上,cleanup
是一个系统内置函数,函数签名类似: void cleanup(void (*)(id *instance))
。可以看到,它的形参是一个函数指针,这个函数指针指向一个没有返回值、形参为id *的函数。
cleanup
函数的作用是在修饰的对象的作用域结束时,调用传递给cleanup
函数的形参函数。而且,cleanup
是先于这个对象的dealloc调用的。假如一个作用域内有若干个被cleanup
修饰的变量,形参函数的调用顺序是后入先出的栈式顺序。
例如:
/// code
inline static void personClean(__strong Person **aPerson) {
NSLog(@"Person clean now, is %p", *aPerson);
}
{
Person *person __attribute((cleanup(personClean))) = Person.new;
} /// mark - 此处person对象作用域结束,生命周期结束
/// output
Person clean now, is 0x......
上例中,定义了一个c函数为personClean
,该函数返回值为空、形参为指向Person对象的二重指针,并在该函数中打印了入参对象。
下面的代码,在{}
作用域中定义了person对象,并使用__attribute((cleanup(personClean)))
修饰了该对象,表示在该对象生命周期结束时,应将person对象作为入参调用personClean
函数。
当代码执行到mark -
处时,person对象的生命周期即将结束,此时会cleanup
函数会调用personClean
函数,执行相关操作。
cleanup实战技巧
1. 保留代码,最后执行
上面提到了,一个作用域内存在多个cleanup
操作时,在作用域结束时会按照后进先出
的顺序执行入参函数。
利用这个特性,就可以在作用域开始时就将作用域结束时执行的逻辑设定好。例如,在一个函数中执行加锁操作,如果函数行数特别多,以防在函数结束时忘记解锁,可以通过cleanup
函数提前设定函数结束时的解锁操作。
伪代码如下:
inline static void lockClean(__strong Lock **lock) {
[*lock unlock];
}
void myFunction() {
Lock *lock __attribute((cleanup(lockClean)), unused) = Lock.new;
[lock lock];
} /// mark - 执行到这里时,将自动调用lockClean函数执行解锁
2.实现保留清理操作的块
上面提到了cleanup
函数的签名类似: void cleanup(void (*)(id *instance))
。id
在objc中,可以修饰任意类型。也就是说,cleanup
函数同样适用于block
变量。
我们可以定义一个宏,如下:
#define OnExit \
__strong dispatch_block_t block __attribute((cleanup(blockClean), unused)) = ^
同样的,需要定义一个传递给cleanup
函数的清理函数:
inline static void blockClean(__strong dispatch_block_t *block) {
!(*block) ? : (*block)();
}
在blockClean
函数中,只是执行了传递的入参block
,这样就可以将清理逻辑在定义入参的地方处理了,提高了代码的内聚。
完成上两步后,再来重写一次在作用域结束时,自动进行解锁的伪代码:
void myFunction() {
Lock *lock __attribute((cleanup(lockClean)), unused) = Lock.new;
OnExit {
[lock unlock];
};
} /// mark - 执行到这里时,将自动调用blockClean函数,而后回调到OnExit定义的块中执行解锁
可以看到,和第一点那种方式不同的是:使用cleanup
函数修饰block
类型的变量,将对象作用域结束时的清理逻辑和对象的定义集中到了一起,这样在清理逻辑中也能使用同样的上下文。