Мое решение было взято полностью из решения Берика, поэтому он получает всю заслугу здесь.Я просто почувствовал, что для проблемного пространства «рекурсивных блоков» нужна более общая структура (которую я не нашел в другом месте), в том числе для асинхронного случая, который описан здесь.
Использование этих трех первых определенийделает возможным использование четвертого и пятого методов - которые просто примеров - невероятно простой, надежный и (я считаю) безопасный для памяти способ вернуть любой блок в произвольные пределы.
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
,который должен быть установлен в какой-то момент для выхода из рекурсии (знакомый шаблон в некоторых итераторах блоков Какао).
- (void)recurseTo:(int)max
{
__block int i = 0;
void (^recursable)(BOOL *) = ^(BOOL *stop) {
//Do
NSLog(@"testing: %d", i);
//Criteria
i++;
if ( i >= max ) {
*stop = YES;
}
};
recurse(recursable);
}
+ (void)makeSizeGoldenRatio:(UIView *)view
{
__block CGFloat fibonacci_1_h = 1.f;
__block CGFloat fibonacci_2_w = 1.f;
recurse(^(BOOL *stop) {
//Criteria
if ( fibonacci_2_w > view.superview.bounds.size.width || fibonacci_1_h > view.superview.bounds.size.height ) {
//Calculate
CGFloat goldenRatio = fibonacci_2_w/fibonacci_1_h;
//Frame
CGRect newFrame = view.frame;
newFrame.size.width = fibonacci_1_h;
newFrame.size.height = goldenRatio*newFrame.size.width;
view.frame = newFrame;
//Done
*stop = YES;
NSLog(@"Golden Ratio %f -> %@ for view", goldenRatio, NSStringFromCGRect(view.frame));
} else {
//Iterate
CGFloat old_fibonnaci_2 = fibonacci_2_w;
fibonacci_2_w = fibonacci_2_w + fibonacci_1_h;
fibonacci_1_h = old_fibonnaci_2;
NSLog(@"Fibonnaci: %f %f", fibonacci_1_h, fibonacci_2_w);
}
});
}
recurseAfter
работает почти так же, хотя я не буду предлагать надуманный пример здесь,Я использую все три из них без проблем, заменяя мой старый шаблон -performBlock:afterDelay:
.