__block
关键字在 Objective-C 中的确切含义是什么?我知道它允许你在块内修改变量,但我想知道...
- 它具体告诉编译器什么?
- 它还有其他作用吗?
- 如果这是它唯一的作用,那么为什么需要它呢?
- 文档中是否有相关内容?(我找不到)
__block
关键字在 Objective-C 中的确切含义是什么?我知道它允许你在块内修改变量,但我想知道...
这告诉编译器,任何被标记为__block
的变量在其所在的代码块内部使用时必须以特殊方式对待。通常,用于代码块中的变量及其内容会被复制,因此对这些变量所做的任何修改都不会显示在代码块外面。当它们被标记为 __block
时,在代码块内部进行的修改也可以在其外部看到。
有关示例和更多信息,请参见苹果公司的Blocks Programming Topics中的The __block Storage Type。
重要示例如下:
extern NSInteger CounterGlobal;
static NSInteger CounterStatic;
{
NSInteger localCounter = 42;
__block char localCharacter;
void (^aBlock)(void) = ^(void) {
++CounterGlobal;
++CounterStatic;
CounterGlobal = localCounter; // localCounter fixed at block creation
localCharacter = 'a'; // sets localCharacter in enclosing scope
};
++localCounter; // unseen by the block
localCharacter = 'b';
aBlock(); // execute the block
// localCharacter now 'a'
}
在这个例子中,localCounter
和localCharacter
都在调用块之前被修改了。然而,在块内部,只有对localCharacter
的修改是可见的,这要归功于__block
关键字。相反,块可以修改localCharacter
,并且这种修改在块外部是可见的。localCounter
,但它会修改 localCharacter
。另外,请注意块中 localCounter
的值:它是42,尽管变量在块被调用之前增加了,但是在块被创建时(值被“捕获”时)增加的。 - DarkDust@bbum在一篇博客文章中深入介绍了块并涉及了__block存储类型。
__block是一个独立的存储类型
像static、auto和volatile一样,__block是一种存储类型。它告诉编译器变量的存储需要进行不同的管理。
...
然而,对于__block变量,块不会进行保留操作。你需要根据需要进行保留和释放。
...
至于使用场景,你会发现__block
有时用于避免保留周期,因为它不会保留参数。一个常见的例子是使用self。
//Now using myself inside a block will not
//retain the value therefore breaking a
//possible retain cycle.
__block id myself = self;
当您不使用__block时,块会复制变量(按值调用),因此即使您在其他地方修改变量,块也看不到更改。
__block使块保留对变量的引用(按引用调用)。
NSString* str = @"hello";
void (^theBlock)() = ^void() {
NSLog(@"%@", str);
};
str = @"how are you";
theBlock(); //prints @"hello"
在这两种情况下,您需要使用__block:
如果您想要在块内修改变量并希望它在外部可见:
__block NSString* str = @"hello";
void (^theBlock)() = ^void() {
str = @"how are you";
};
theBlock();
NSLog(@"%@", str); //prints "how are you"
如果你想要在声明块后修改变量,并且希望块可以看到这些更改:
__block NSString* str = @"hello";
void (^theBlock)() = ^void() {
NSLog(@"%@", str);
};
str = @"how are you";
theBlock(); //prints "how are you"
__block
标记的自动变量会被编译器转换为一个自动释放的对象,其生命周期与块一样长,可能超出声明范围。此外,它每次都会被创建,因此创建的每个theBlock
实例都将引用不同的str
变量。 - James Bucanek__block是一种存储限定符,可以有两种用法:
标记变量存储在原始变量的词法作用域和在该作用域内声明的任何块之间共享的存储中。Clang将生成一个结构来表示此变量,并按引用(而不是按值)使用此结构。
在MRC中,__block可用于避免块捕获的对象变量被保留。注意这对ARC无效。在ARC中,应改用 __weak 。
您可以参考苹果文档获取详细信息。
{
int stackVariable = 1;
blockName = ^()
{
stackVariable++;
}
}
如果代码块内的堆栈变量没有使用__block(存储修饰符)进行声明,那么会出现"variable is not assignable"这样的错误,因为堆栈变量默认是不可变的。
在变量声明之前添加__block可以使其在代码块内可变,例如__block int stackVariable=1;
这意味着它作为前缀的变量可以在块内使用。
__block
。 - DarkDust__block
应该如何翻译成Swift: "闭包 [在Swift中] 与块 [在Objective-C中] 具有类似的捕获语义,但存在一个关键区别:变量是可变的,而不是被复制的。换句话说,Objective-C中__block的行为是Swift中变量的默认行为。”来自苹果的书:《使用Swift与Cocoa和Objective-C》(Swift 2.2)。 - Jari Keinänen