iOS自动解锁的实现

今天用clang将Objective-C语言转换成Cpp时,发现一个对变量的作用域有趣的用法。当我们用@autorelease{}时,将转换为以下形式(已移除无关代码):

问题来源

int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
        /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
            /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
            }
        }
    }
    return 0;
}
那么 __AtAutoreleasePool 是什么呢?

struct __AtAutoreleasePool {
  __AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
  ~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
  void * atautoreleasepoolobj;
};
好家伙!原来是一个在构造函数里面push了一个新的自动释放池,并在析构函数里面pop它。那么开头的 {__AtAutoreleasePool __autoreleasepool; /*这里是代码 */ }就好理解了:这里声明了一个 __AtAutoreleasePool类型的 __autoreleasepool变量,通过变量在初始化的时候调用构造函数来创建一个新的自动释放池,并在变量的作用域结束时,自动调用析构函数来释放自动释放池。

应用

那么还有什么地方可以用这种小技巧来提高开发效率呢? ——锁。

@interface AutoLock : NSObject
+ (instancetype)lock:(NSLock *)lock;
- (instancetype)initWithLock:(NSLock *)lock;
@end

@implementation AutoLock
{
    id _lock;
}
+ (instancetype)lock:(NSLock *)lock
{
    return [[self alloc] initWithLock:lock];
}
- (instancetype)initWithLock:(NSLock *)lock
{
    if (self = [super init]) {
        _lock = lock;
        [_lock lock];
    }
    return self;
}
- (void)dealloc
{
    [_lock unlock];
}

//使用
- (void)doSomething
{
    AutoLock *autolock = [AutoLock lock:lock];
    //以下为加锁后的代码
}
这时候编译器会提示 autolock 变量未使用。
可以使用以下三种形式消除警告

  1. 使用#pragma clang diagnostic ignored "-Wunused-variable"
  2. 使用 #define UNUSED(_ivar) (void)(_ivar); 
  3. 使用编译器变量属性 __attribute__((unused))

进阶应用

查阅了GCC关于__attribute__说明,发现__attribute__((cleanup_function))属性。GCC说明如下:

cleanup (cleanup_function) 

The cleanup attribute runs a function when the variable goes out of scope. This attribute can only be applied to auto function scope variables; it may not be applied to parameters or variables with static storage duration. The function must take one parameter, a pointer to a type compatible with the variable. The return value of the function (if any) is ignored. If -fexceptions is enabled, then cleanup_function is run during the stack unwinding that happens during the processing of the exception. Note that the cleanup attribute does not allow the exception to be caught, only to perform an action. It is undefined what happens if cleanup_function does not return normally.

简单来说,就是在修饰的变量作用域结束时,将自动调用cleanup_function函数。cleanup_function必须带有一个指向修饰变量的地址的参数。这时候,可以传入一个block的变量地址,并在cleanup_function执行这个block。

static void _autoLock(void (^ __strong *lockBlock)()) {
    (*lockBlock)();
}
为了可以将这个函数作为清理函数,这就需要我们定义的变量是一个void (^ __strong)() 类型的block。并且在block里面解锁。

NSLock *lock = [[NSLock alloc] init];
[lock lock];
void (^__strong autoLock)() __attribute__((cleanup(_autoLock), unused)) = ^{
    //变量作用域结束后运行的代码
    [lock unlock];
};
我们还可以将上面的定义成一个宏

#define AUTO_LOCK(__lock) \
[__lock lock]; \
void (^ __strong autoLock)() __attribute__((cleanup(_autoLock), unused)) = ^\
{[__lock unlock];};

使用如下

- (void)doSomething
{
    AUTO_LOCK(lock);
    //以下为加锁代码
    ...
}

参考:

http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html
http://stackoverflow.com/questions/21383695/why-cleanup-attribute-of-gcc-clang-can-not-be-used-with-function-parameter

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值