我更喜欢使用定点组合器结构来写块递归。这样,当我忘记在递归结束时将块设置为零时,我不必乱用__block变量或冒着保留周期的风险。所有这一切都归功于Mike Ash,他分享了这个code snippet。
这里是我的版本他的代码(我放在全局共享文件,这样我就可以随时随地存取此功能):
// From Mike Ash's recursive block fixed-point-combinator strategy (https://gist.github.com/1254684)
dispatch_block_t recursiveBlockVehicle(void (^block)(dispatch_block_t recurse))
{
// assuming ARC, so no explicit copy
return ^{ block(recursiveBlockVehicle(block)); };
}
typedef void (^OneParameterBlock)(id parameter);
OneParameterBlock recursiveOneParameterBlockVehicle(void (^block)(OneParameterBlock recurse, id parameter))
{
return ^(id parameter){ block(recursiveOneParameterBlockVehicle(block), parameter); };
}
我知道这看起来超级怪异和混乱......但它不是一旦你明白它就太糟糕了。这里有一个简单的递归块可能是什么样子:
dispatch_block_t run = recursiveBlockVehicle(^(dispatch_block_t recurse)
{
if (! done)
{
// Continue recursion
recurse();
}
else
{
// End of recursion
}
});
run();
当你调用recursiveBlockVehicle
,你传递包含您的代码块。recursiveBlockVehicle
的工作就是利用这个块,你过去了,做三件事情:
- 执行块
- 背透
recursiveBlockVehicle
传递块,并通过该结果作为参数传递给块
- 包封物步骤1和2个简单的块中,并返回
现在,你的块的代码中,如果你调用特殊recurse
块参数,你又一遍呼唤自己的块(实现递归) 。这种策略的好处在于内存管理非常简单。使用参数将自己的代码传回给自己可以降低保留周期的风险。我使用这种方法,而不是定义我的代码的__block变量,因为恐怕我可能会忘记在递归结束时将__block变量设置为零,并导致令人讨厌的保留周期。
考虑到这一点,这是我将如何实现你的函数:
OneParameterBlock run = recursiveOneParameterBlockVehicle(^(OneParameterBlock recurse, id parameter)
{
NSNumber *offset = parameter;
[noteStore
findNotesMetadataWithFilter:filter
offset:offset.intValue
maxNotes:100
resultSpec:resultSpec
success:^(EDAMNotesMetadataList *metadataList)
{
for (EDAMNoteMetadata *metadata in metadataList.notes)
{
NSDate *timestamp = [NSDate endateFromEDAMTimestamp:metadata.updated];
if (timestamp.timeIntervalSince1970 > date.timeIntervalSince1970)
{
[array addObject:metadata];
}
else
{
arrayComplete = YES;
}
}
//I need it to loop this code, increasing the offset, until the array is complete.
if (! arrayComplete)
{
recurse([NSNumber numberWithInt:offset.intValue + 100]);
}
}
failure:^(NSError *error)
{
NSLog(@"Failure: %@", error);
}];
});
run(@0);
再次注意,你不打电话块本身的内部callback
(块对象)。之所以这样,是因为该块作为参数recurse
传递自己并执行recurse
是您如何实现递归。
而且,(如果你实际上已经远远阅读并希望看到更多的),这里的一对FPC维基百科页面:http://en.wikipedia.org/wiki/Fixed-point_combinator
最后,我没有亲自测试了__block变量的保留周期问题。然而,罗布Mayoff没有在这个问题上一个梦幻般的分析:https://stackoverflow.com/a/13091475/588253
你如何知道你是否需要获取更多物品?你对这些物品做什么?这个过程如何开始呢?你在运行什么线程或队列?你用什么API从服务器获取项目? –
它检查每个返回项目的日期。如果它早于特定日期,则需要在返回之前收集更多项目。 – Andrew