黑魔法__attribute__((cleanup))有讲如何使用cleanup
来简化使用lock代码。__attribute__
这个修饰符颇有用,前段时间集中写了一些东西收集这些有意思__attribute__
。戳这里git
今天展现一种另外的方法达到这个目的。最终代码放在了个人githubgithub
#define CONCAT(x, y) x##y #define MACRO_CONCAT(x,y) CONCAT(x,y) @interface AutoUnlockObject : NSObject { id<NSLocking> _lock; } - (id) initWithLock:(id<NSLocking>)theLock; @end @implementation AutoUnlockObject - (id) initWithLock:(id<NSLocking>)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。segmentfault
- (void) dosth{ AUTOLOCK(self.lock); //do actual work you want below }
__Counter__
是一个gcc提供的宏,在此用于产生一个文件内惟一的数字,这样就能够在同一个函数里屡次使用AUTOLOCK
lock不一样的锁。CONCAT
和MACRO_CONCAT
是一种惯用的链接Macro的手法,很少说了。函数
这种方法依赖于代码块的长度,若是要分段使用屡次lock同一把锁。那就方法以下:atom
- (void) dosth{ { AUTOLOCK(self.lock); //do actual work you want below } { AUTOLOCK(self.lock); //do actual work you want below } }
若是还嫌麻烦,那就只能用这个函数:spa
void lockAndDo(id<NSLocking>lock,dispatch_block_t block) { if (lock) { AUTOLOCK(lock); if (block) { block(); } }else{ if (block) { block(); } } }
使用时:code
lockAndDo(lock, ^{ //do actual work you want here });
这样以来就跟@synchronized
很像了。blog
@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__,若是不分代码块的话,一个做用域里只能用一个。get
更新一下,改为这种就行了,
#define AUTOLOCK3(lock) \ [[AutoUnlockObject2 alloc] initWithLock:lock].block = ^ //usage AUTOLOCK3(lock){ NSLog(@"hi1"); }; AUTOLOCK3(lock){ NSLog(@"hi2"); };
恩.
All is well that ends well
不过话说回来,如今用lock的时候,已经不太多了。C++的代码基本也能够用相似实现。
原做写于segmentfault 连接