Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 异步调度递归块_Iphone_Objective C_Grand Central Dispatch_Objective C Blocks - Fatal编程技术网

Iphone 异步调度递归块

Iphone 异步调度递归块,iphone,objective-c,grand-central-dispatch,objective-c-blocks,Iphone,Objective C,Grand Central Dispatch,Objective C Blocks,假设我运行以下代码: __block int step = 0; __block dispatch_block_t myBlock; myBlock = ^{ if(step == STEPS_COUNT) { return; } step++; dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC / 2); dispatch

假设我运行以下代码:

__block int step = 0;

__block dispatch_block_t myBlock;

myBlock = ^{
     if(step == STEPS_COUNT)
     {
         return;
     }

     step++;
     dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC / 2);
     dispatch_after(delay, dispatch_get_current_queue(), myBlock);
};

dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC / 2);
dispatch_after(delay, dispatch_get_current_queue(), myBlock);
从外部调用该块一次。当到达内部调用时,程序崩溃,没有任何细节。如果我在任何地方都使用直接调用而不是GCD调度,那么一切都可以正常工作

我还试着用块的副本给dispatch_打电话。我不知道这是否是朝着正确的方向迈出的一步,但这还不足以让它起作用


想法?

我认为,如果你想让块继续存在,就必须复制它(当你不想让它再调用自己时释放它)。

看起来除了延迟变量之外,没有什么问题。块始终使用在第1行生成的相同时间。如果您想延迟调度区块,则必须每次调用dispatch_

    step++;
    dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC / 2);
    dispatch_after(delay, dispatch_get_current_queue(), myBlock);
};
myBlock = Block_copy(^{
    ...
});
编辑:

我明白

块由块文本存储在堆栈中。myBlock变量替换堆栈中块的地址

从myBlock变量(堆栈中的地址)复制块后的第一次分派\u。这个地址现在是有效的。该块在当前范围内

在那之后,这个区块的范围就扩大了。myBlock变量此时的地址无效。将复制的块放入堆后分派\u。它是安全的

然后,块中的第二个dispatch_尝试从myBlock变量复制无效地址,因为堆栈中的块已被限定范围。它将在堆栈中执行损坏的块

因此,您必须阻止并复制块

    step++;
    dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC / 2);
    dispatch_after(delay, dispatch_get_current_queue(), myBlock);
};
myBlock = Block_copy(^{
    ...
});
别忘了积木,当你不再需要它的时候,把积木释放出来

Block_release(myBlock);

在试图解决这个问题时,我发现了一段代码,它解决了许多与递归块相关的问题。我无法再次找到源代码,但仍有代码:

// in some imported file
dispatch_block_t RecursiveBlock(void (^block)(dispatch_block_t recurse)) {
    return ^{ block(RecursiveBlock(block)); };
}

// in your method
dispatch_block_t completeTaskWhenSempahoreOpen = RecursiveBlock(^(dispatch_block_t recurse) {
    if ([self isSemaphoreOpen]) {
        [self completeTask];
    } else {
        double delayInSeconds = 0.3;
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
        dispatch_after(popTime, dispatch_get_main_queue(), recurse);
    }
});

completeTaskWhenSempahoreOpen();

RecursiveBlock
允许使用非参数块。它可以为单个或多个参数块重写。使用这种结构简化了内存管理,例如,不可能有保留周期。

我的解决方案完全源自Berik,因此他在这里获得了所有荣誉。我只是觉得“递归块”问题空间(我在其他地方没有发现)需要一个更通用的框架,包括异步情况,这里介绍了异步情况

使用这三个第一个定义使得第四个和第五个方法——它们只是示例——成为可能,这是一种非常简单、简单且(我相信)内存安全的方法,可以将任何块递归到任意限制

dispatch_block_t RecursiveBlock(void (^block)(dispatch_block_t recurse)) {
    return ^() {
        block(RecursiveBlock(block));
    };
}

void recurse(void(^recursable)(BOOL *stop))
{
    // in your method
    __block BOOL stop = NO;
    RecursiveBlock(^(dispatch_block_t recurse) {
        if ( !stop ) {
            //Work
            recursable(&stop);

            //Repeat
            recurse();
        }
    })();
}

void recurseAfter(void(^recursable)(BOOL *stop, double *delay))
{
    // in your method
    __block BOOL stop = NO;
    __block double delay = 0;
    RecursiveBlock(^(dispatch_block_t recurse) {
        if ( !stop ) {
            //Work
            recursable(&stop, &delay);

            //Repeat
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), recurse);
        }
    })();
}
您将注意到,在以下两个示例中,与递归机制交互的机制非常轻量级,基本上相当于必须在
recurse
中包装一个块,并且该块必须使用
BOOL*stop
变量,该变量应在某个点设置以退出递归(一些Cocoa块迭代器中的熟悉模式)


recurseAfter
的工作原理基本相同,不过这里我不会提供一个精心设计的示例。我正在使用这三种模式,取代我以前的
-performBlock:afterDelay:
模式。

选择自定义调度源

dispatch_queue_t queue = dispatch_queue_create( NULL, DISPATCH_QUEUE_SERIAL );
__block unsigned long steps = 0;
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, queue);
dispatch_source_set_event_handler(source, ^{

    if( steps == STEPS_COUNT ) {
        dispatch_source_cancel(source);
        return;
    }

    dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC / 2);
    dispatch_after(delay, queue, ^{
        steps += dispatch_source_get_data(source);
        dispatch_source_merge_data(source, 1);
    });

});

dispatch_resume( source );
dispatch_source_merge_data(source, 1);

很好。我修改了代码,但在执行递归调用时它仍然崩溃。事实上,您的代码在我的环境中运行良好。您在哪里/如何调用它?我将代码更改为使用dispatch_block__t。我设置了一个单独的项目来测试此问题。我在视图控制器的viewDidLoad方法中调用了所有代码。我现在正在使用此成功完全避免此块中的所有“捕获”可能会导致“保留周期”警告。不知道这是否对其他人有帮助,但这里有一种方法可以在递归发生时在您控制的位置执行递归块。请考虑双起始…
extern void recurseTrigger(void(^recursable)(void(^trigger)()void){RealsivBug(^(DexChuxBulkIt递归){//工作可递归(递归);})();} /代码>我相信您的来源是不可模仿的Mike Ash: