起
有讲如何使用cleanup
来简化使用lock代码。
__attribute__
这个修饰符很有用,前段时间集中写了一些东西收集这些有意思__attribute__
。戳 今天展示一种另外的方法达到这个目的。最终代码放在了我的
实现
#define CONCAT(x, y) x##y#define MACRO_CONCAT(x,y) CONCAT(x,y)@interface AutoUnlockObject : NSObject { id_lock;}- (id) initWithLock:(id )theLock;@end@implementation AutoUnlockObject- (id) initWithLock:(id )theLock{ self = [super init]; _lock = theLock; [_lock lock]; return self;}- (void) dealloc{ [_lock unlock];}@end#define AUTOLOCK(lock) \__unused AutoUnlockObject* MACRO_CONCAT(tmpObject,__COUNTER__) = [[AutoUnlockObject alloc] initWithLock:lock];
解释
利用ARC的特性,在离开代码块时,tmpObject
会自动释放。这样-dealloc
中的unlock回触发,从而实现自动unlock。
- (void) dosth{ AUTOLOCK(self.lock); //do actual work you want below}
__Counter__
是一个gcc提供的宏,在此用于产生一个文件内唯一的数字,这样就可以在同一个函数里多次使用AUTOLOCK
lock不同的锁。CONCAT
和MACRO_CONCAT
是一种惯用的连接Macro的手法,不多说了。
这种方法依赖于代码块的长度,如果要分段使用多次lock同一把锁。那就方法如下:
- (void) dosth{ { AUTOLOCK(self.lock); //do actual work you want below } { AUTOLOCK(self.lock); //do actual work you want below }}
如果还嫌麻烦,那就只能用这个函数:
void lockAndDo(idlock,dispatch_block_t block){ if (lock) { AUTOLOCK(lock); if (block) { block(); } }else{ if (block) { block(); } }}
使用时:
lockAndDo(lock, ^{ //do actual work you want here });
这样以来就跟@synchronized
很像了。
增强
@interface AutoUnlockObject2 : AutoUnlockObject @property (nonatomic,copy) dispatch_block_t block;@end@implementation AutoUnlockObject2- (void) dealloc{ if (self.block) self.block(); [_lock unlock];}@end#define AUTOLOCK2(lock) \__unused AutoUnlockObject2* tmpObject = [[AutoUnlockObject2 alloc] initWithLock:lock];\tmpObject.block = ^
增强一下,使用起来跟@synchronized
和cleanup
的方案基本差不太多了:
AUTOLOCK2(lock){ NSLog(@"hi");};
美中不足:没有使用__COUNTER__,如果不分代码块的话,一个作用域里只能用一个。
更新一下,改成这种就好了,
#define AUTOLOCK3(lock) \[[AutoUnlockObject2 alloc] initWithLock:lock].block = ^//usageAUTOLOCK3(lock){ NSLog(@"hi1");};AUTOLOCK3(lock){ NSLog(@"hi2");};
恩.
All is well that ends well
总结
不过话说回来,现在用lock的时候,已经不太多了。C++的代码基本也可以用类似实现。
原作写于segmentfault