老谭笔记

利用ARC解决遗忘unlock的毛病

我们在使用lock的时候会有这样的情况:因为某方法内部逻辑较为复杂,会有很多地方return,稍不留神都会漏掉一次unlock的操作,在查看一些C++源码时发现一种比较优雅的设计,在某个方法或一个代码块需要锁时,不直接对锁进行操作,而是通过创建一个局部对象来管理这个锁,我们将这个对象称之为”哨兵”,该对象在构造函数中执行lock操作,而在析构函数中执行unlock,这样当我们需要加锁时只需要创建这个对象,当函数return后或代码块结束时,因为局部对象在超出作用域后释放,便自动完成了unlock的动作。

而在Objective-C中我们不能创建局部对象,但利用ARC的特性却也可以达到超出作用域自动释放的特性。
以下是”哨兵”类的实现:

@interface QMGuard : NSObject
{
    id<NSLocking> lock;
}
@end

@implementation QMGuard

- (id)initWithLock:(id<NSLocking>)obj
{
    self = [super init];
    if (self)
    {
        lock = obj;
        [lock lock];
    }
    return self;
}

- (void)dealloc
{
    [lock unlock];
}

@end

以下是我们在使用锁的时候:

//为了方便使用
#define QUARD(lock) \
QMGuard *_guard_ = [[QMGuard alloc] initWithLock:lock];\
NSAssert(_guard_, @"_guard_ invaild");

@interface MyClass : NSObject
{
    NSLock *lock;
}
@end

@implementation MyClass

- (id)init
{
    self = [super init];
    if (self)
    {
        lock = [[NSLock alloc] init];
    }
    return self;
}

- (void)test1
{
    QUARD(lock)
    NSLog(@"do test1");
}

- (void)test2
{
    QUARD(lock)
    NSLog(@"do test2");
}

@end