Objective-C 块内的代码如何引用块对象本身?

发布于 2024-10-20 19:13:27 字数 54 浏览 2 评论 0原文

self 只是块内的捕获变量,并不引用块本身,那么块如何在没有显式捕获变量的情况下引用自身呢?

self is merely a captured variable inside a block and doesn't reference the block itself, so how does a block reference itself without having an explicit captured variable for that purpose?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

挽清梦 2024-10-27 19:13:27
__block void(^strawberryFields)();
strawberryFields = [^{ strawberryFields(); } copy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
               strawberryFields);
  • 您使用__block,因为该块将在创建该块时复制strawberryFields的值,该副本将在赋值之前.

  • 您还必须在任何其他复制操作之前复制该块,否则您最终会得到一个引用堆栈上原始版本的块。

  • 请注意,上面的代码泄漏了区块。在某个地方,需要释放该块来平衡副本。

__block void(^strawberryFields)();
strawberryFields = [^{ strawberryFields(); } copy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
               strawberryFields);
  • you use the __block because the block will make a copy of the value of strawberryFields when the block is created which will be before the assignment.

  • you also must copy the block prior to any other copy operation or else you'll end up with a block that references the on-stack original version.

  • note that the above code leaks the block. Somewhere, there needs to be a release of that block to balance the copy.

樱花落人离去 2024-10-27 19:13:27

我发现这种模式对于 ARC(自动引用计数)来说既有效又稳定,无论是在调试还是发布版本中。

-(void) someMethod
{
    // declare a __block variable to use inside the block itself for its recursive phase.
    void __block (^myBlock_recurse)();

    // define the block
    void (^myBlock)() = ^{
        // ... do stuff ...
        myBlock_recurse(); // looks like calling another block, but not really.
    };

    // kickstart the block
    myBlock_recurse = myBlock; // initialize the alias
    myBlock(); // starts the block
}

最初,我尝试将 __block 修饰符添加到 myBlock 中,并直接使用该变量在块的实现中进行递归。这适用于 ARC 调试版本,但在发布版本上会因 EXC_BAD_ACCESS 而中断。另一方面,删除 __block 修饰符会引发“被块捕获时未定义变量”警告(并且我不愿意运行它和测试)。

I found this pattern to work and stable for ARC (automatic reference counting), both in Debug and Release builds.

-(void) someMethod
{
    // declare a __block variable to use inside the block itself for its recursive phase.
    void __block (^myBlock_recurse)();

    // define the block
    void (^myBlock)() = ^{
        // ... do stuff ...
        myBlock_recurse(); // looks like calling another block, but not really.
    };

    // kickstart the block
    myBlock_recurse = myBlock; // initialize the alias
    myBlock(); // starts the block
}

Initially I tried just putting a __block modifier to myBlock and use that variable directly to recurse within the block's implementation. That works on the ARC Debug build but breaks with an EXC_BAD_ACCESS on the Release build. On the other hand removing the __block modifier raises a "variable not defined when captured by block" warning (and I was reluctant to run it and test).

九厘米的零° 2024-10-27 19:13:27

我以前从未尝试过此操作,并且不能 100% 确定它是否有用(如果有效),但例如:

typedef void (^BasicBlock)(void);

__block BasicBlock testBlock;
testBlock  = ^{NSLog(@"Testing %p", &testBlock);};
testBlock();

您可能已使用 __block 声明变量以防止自保留循环。

I have never tried this before and not 100% sure it's useful, if valid, but for example:

typedef void (^BasicBlock)(void);

__block BasicBlock testBlock;
testBlock  = ^{NSLog(@"Testing %p", &testBlock);};
testBlock();

You probably have declare the variable with __block to prevent self-retain cycle.

相权↑美人 2024-10-27 19:13:27

该块需要某种方法来消除它自己的引用。通常,这是通过将块存储在类的属性中来完成的。

有时您可能不想使用某个属性。以下是在没有属性的情况下如何执行此操作:

    __weak id weakSelf = self;
    __block id block = ^{

        if(weakSelf) {

            // .. do whatever

            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), block);
        }
        else {

            block = nil;
        }
    };

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), block);

要记住的关键是所有代码路径都必须指向 block = nil。为此,我们每 5 秒调用一次该块,直到weakSelf 变为 nil。

The block needs some way to nil out its own reference. Typically it is done by storing the block in a property of the class.

Sometimes you can prefer to not use a property. Here is how you do it without a property:

    __weak id weakSelf = self;
    __block id block = ^{

        if(weakSelf) {

            // .. do whatever

            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), block);
        }
        else {

            block = nil;
        }
    };

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), block);

The key thing to keep in mind is that all code paths must lead to a block = nil. We do that here by calling the block every 5 seconds until weakSelf turns nil.

无边思念无边月 2024-10-27 19:13:27

请注意,在 ARC 中,情况略有不同 - 与 MRC 不同,ARC 中默认保留 __block 对象指针变量。这样,就会造成循环引用。该块有必要捕获对其自身的弱引用(使用__weak),以避免出现保留周期。

然而,我们仍然需要在某个地方对该块进行强引用。如果没有强引用,则该块(由于复制而位于堆上)将被释放。因此,我们需要两个变量,一强一弱,并在块内使用弱变量来引用自身:

__block __weak void(^weakBlock)();
void(^myBlock)();
weakBlock = myBlock = [^{ weakBlock(); } copy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
               myBlock);

Note that in ARC, it's a little different -- __block object pointer variables are by default retained in ARC, unlike in MRC. Thus, it will cause a retain cycle. It is necessary for the block to capture a weak reference to itself (using __weak) in order to not have a retain cycle.

However, we still need a strong reference to the block somewhere. If there are no strong references, the block (which is on the heap since it's copied) will be deallocated. Thus, we need two variables, one strong and one weak, and inside the block use the weak one to reference itself:

__block __weak void(^weakBlock)();
void(^myBlock)();
weakBlock = myBlock = [^{ weakBlock(); } copy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
               myBlock);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文