为什么 objective-c 的块不能动态捕获值?
Why objective-c's block cannot capture values dynamically?
我想在 objective-c 中实现 defer
。这是我的代码:
/**
RAII : ABC->~ABC
*/
@interface DeferImpl_ : NSObject
/**
* init with a callback
*
* @return
*/
-(instancetype) initWithCallback:(void(^)())callback;
/**
* a callback
*/
@property(nonatomic, copy) void(^callback)();
@end
/**
* Defer
*
* @param X { statement; statement; ... }
*
* @return
*/
#define DEFER(X) [[DeferImpl_ alloc] initWithCallback:^X]
#define SAFE_INVOKE(x) do{if(x){(x)();}}while(0)
@implementation DeferImpl_
/**
* invoke callback
*/
-(void) dealloc {
SAFE_INVOKE(self.callback);
}
-(instancetype) initWithCallback:(void(^)())callback {
self = [super init];
self.callback = callback;
return self;
}
@end
实现简单,似乎易于使用。
但它有问题!。
我感到沮丧的事情来了。
int main(void)
{
NSInteger count = 0;
DEFER({
NSLog(@"Defer: %@", @(count));
});
count = 123;
NSLog(@"Before defer block!");
return 0;
}
日志是:
2017-01-12 17:31:32.401 test[73724:18571479] Defer: 0
2017-01-12 17:31:32.402 test[73724:18571479] Before defer block!
所以有没有人能告诉我为什么 count
仍然是 0 块?
您已将大部分工作隐藏到宏中(这不是一种好的编程风格!)并且您缺少基本点 - DEFER
立即调用该块,甚至在到达 count = 123
之前。
如果您不将 [DeferImpl_ alloc]
的结果赋值给任何变量,它将立即释放,并立即调用该块。
你现在的代码和直接写一样:
NSInteger count = 0;
NSLog(@"Defer: %@", @(count));
count = 123;
NSLog(@"Before defer block!");
如果您将代码更改为:
NSInteger count = 0;
id x = DEFER({
NSLog(@"Defer: %@", @(count));
});
count = 123;
NSLog(@"Before defer block!");
您的结果将是:
Before defer block!
Defer: 0
现在,为什么该值仍然为零?因为块通过值 捕获变量 。要捕获引用,您必须添加 __block
:
__block NSInteger count = 0;
id x = DEFER({
NSLog(@"Defer: %@", @(count));
});
count = 123;
NSLog(@"Before defer block!");
Before defer block!
Defer: 123
我想在 objective-c 中实现 defer
。这是我的代码:
/**
RAII : ABC->~ABC
*/
@interface DeferImpl_ : NSObject
/**
* init with a callback
*
* @return
*/
-(instancetype) initWithCallback:(void(^)())callback;
/**
* a callback
*/
@property(nonatomic, copy) void(^callback)();
@end
/**
* Defer
*
* @param X { statement; statement; ... }
*
* @return
*/
#define DEFER(X) [[DeferImpl_ alloc] initWithCallback:^X]
#define SAFE_INVOKE(x) do{if(x){(x)();}}while(0)
@implementation DeferImpl_
/**
* invoke callback
*/
-(void) dealloc {
SAFE_INVOKE(self.callback);
}
-(instancetype) initWithCallback:(void(^)())callback {
self = [super init];
self.callback = callback;
return self;
}
@end
实现简单,似乎易于使用。 但它有问题!。
我感到沮丧的事情来了。
int main(void)
{
NSInteger count = 0;
DEFER({
NSLog(@"Defer: %@", @(count));
});
count = 123;
NSLog(@"Before defer block!");
return 0;
}
日志是:
2017-01-12 17:31:32.401 test[73724:18571479] Defer: 0
2017-01-12 17:31:32.402 test[73724:18571479] Before defer block!
所以有没有人能告诉我为什么 count
仍然是 0 块?
您已将大部分工作隐藏到宏中(这不是一种好的编程风格!)并且您缺少基本点 - DEFER
立即调用该块,甚至在到达 count = 123
之前。
如果您不将 [DeferImpl_ alloc]
的结果赋值给任何变量,它将立即释放,并立即调用该块。
你现在的代码和直接写一样:
NSInteger count = 0;
NSLog(@"Defer: %@", @(count));
count = 123;
NSLog(@"Before defer block!");
如果您将代码更改为:
NSInteger count = 0;
id x = DEFER({
NSLog(@"Defer: %@", @(count));
});
count = 123;
NSLog(@"Before defer block!");
您的结果将是:
Before defer block!
Defer: 0
现在,为什么该值仍然为零?因为块通过值 捕获变量 。要捕获引用,您必须添加 __block
:
__block NSInteger count = 0;
id x = DEFER({
NSLog(@"Defer: %@", @(count));
});
count = 123;
NSLog(@"Before defer block!");
Before defer block!
Defer: 123