我更喜歡使用定點組合器結構來寫塊遞歸。這樣,當我忘記在遞歸結束時將塊設置爲零時,我不必亂用__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