ChatGPT解决这个技术问题 Extra ChatGPT

“__block”关键字是什么意思?

Objective-C 中的 __block 关键字究竟是什么意思?我知道它允许您修改块内的变量,但我想知道......

它到底告诉编译器什么?它还有其他作用吗?如果这就是它的全部作用,那么为什么首先需要它呢?它在任何地方的文档中吗? (我找不到它)。

检查 here 和“块和变量”部分。
@Code Monkey:我是在专门询问关键字,而不是一般的语法。所以不要认为它真的是重复的。
@Code Monkey:不,这不是重复的。您提到的问题根本没有谈论__block
如果有人想知道 Objective-C 的 __block 应该如何转换为 Swift:”闭包 [在 Swift 中] 与块 [在 Objective-C 中] 具有相似的捕获语义,但在一个关键方面有所不同:变量是可变的而不是复制。换句话说,Objective-C 中 __block 的行为是 Swift 中变量的默认行为。” 来自 Apple 的书:Using Swift with Cocoa and Objective-C (Swift 2.2)。

D
DarkDust

它告诉编译器,任何由它标记的变量在块内使用时都必须以特殊方式处理。通常,块中也使用的变量及其内容会被复制,因此对这些变量所做的任何修改都不会显示在块之外。当它们被标记为 __block 时,在块内完成的修改在块外也可见。

有关示例和更多信息,请参阅 Apple 的 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'
}

在此示例中,localCounterlocalCharacter 都在调用块之前进行了修改。但是,在块内部,由于 __block 关键字,只有对 localCharacter 的修改可见。相反,该块可以修改 localCharacter,并且此修改在该块之外是可见的。


优秀,简洁的解释,和一个非常有用的例子。谢谢!
aBlock如何修改localCounter?它似乎只修改了 CounterGlobal。谢谢
它不会修改 localCounter,但会修改 localCharacter。另外,请注意块中 localCounter 的值:它是 42,即使变量在 在调用块之前但在创建块之后之后增加(那是价值被“捕获”的时候)。
这是一个有用的解释——不过——你能解释一下你的解释中似乎矛盾的陈述吗?您在上面说“aBlock 修改 ...localCounter”,然后在评论中您说“[aBlock] 不修改 localCounter。”它是哪一个?如果它是“未修改”,那么您的答案是否应该被编辑?
通常,没有 __block 的 var 会在创建块时按值捕获并打包到块的“环境”中。但是 __block 变量不会被捕获,无论何时在块内部或外部使用它们时,都会按原样引用它们。
J
Joe

@bbum 在 blog post 中深入介绍了块并涉及 __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;

有关保留周期问题的详细信息,请参阅此帖子:benscheirman.com/2012/01/…。在这种特定情况下,__weak 是否也足够?或许更清楚一点...
最后,关于 __block 可用于避免强引用循环(也称为保留循环)的说法在 ARC 上下文中是完全错误的。由于在 ARC 中 __block 会导致变量被强引用,因此实际上更有可能导致它们。stackoverflow.com/a/19228179/189006
H
Hamidreza Vakilian

当您不使用 __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 = @"你好吗"; };块(); NSLog(@"%@", str); //打印“你好吗” 如果你想在声明块后修改变量并且你希望块看到变化: __block NSString* str = @"hello"; void (^theBlock)() = ^void() { NSLog(@"%@", str); }; str = @"你好吗";块(); //打印“你好吗”


M
Mindy

__block 是一个存储限定符,可以通过两种方式使用:

标记一个变量存在于原始变量的词法范围和在该范围内声明的任何块之间共享的存储中。而 clang 将生成一个结构来表示这个变量,并通过引用(而不是按值)使用这个结构。在 MRC 中,__block 可用于避免保留块捕获的对象变量。小心这对 ARC 不起作用。在 ARC 中,您应该改用 __weak。

您可以参考apple doc了解详细信息。


F
Forge

__block 是一种存储类型,用于使范围内的变量可变,更坦率地说,如果您使用此说明符声明一个变量,它的引用将传递给块而不是只读副本详情见Blocks Programming in iOS


K
Ky.

希望对你有帮助

假设我们有这样的代码:

{
     int stackVariable = 1;

     blockName = ^()
     {
      stackVariable++;
     }
}

它将给出类似“变量不可分配”的错误,因为块内的堆栈变量默认情况下是不可变的。

在声明之前添加 __block(storage modifier) 使其在块内可变,即 __block int stackVariable=1;


C
Community

Block Language Spec

除了新的 Block 类型,我们还为局部变量引入了一个新的存储限定符 __block。 [testme:块文字中的 __block 声明] __block 存储限定符与现有的本地存储限定符 auto、register 和 static 互斥。[testme] 由 __block 限定的变量就像它们在分配的存储中一样,这个存储是在最后一次使用所述变量后自动恢复。实现可以选择一种优化,其中存储最初是自动的,并且仅在引用块的 Block_copy 时“移动”到分配的(堆)存储。这样的变量可能会像正常变量一样发生变异。在 __block 变量是 Block 的情况下,必须假定 __block 变量驻留在分配的存储中,因此假定引用也在分配的存储中的 Block(它是 Block_copy 操作的结果)。尽管如此,如果实现为块提供初始自动存储,则没有规定执行 Block_copy 或 Block_release。这是由于潜在的多个线程试图更新共享变量的固有竞争条件以及围绕处置旧值和复制新值的同步需要。这种同步超出了本语言规范的范围。

有关 __block 变量应该编译成什么的详细信息,请参阅 Block Implementation Spec,第 2.3 节。


你的链接都死了
这不是一个真正的答案,可以充实或删除。谢谢!
R
Rich Allen

这意味着它作为前缀的变量可在块中使用。