本文介绍了如何使用块处理循环代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些需要使用块的代码。该块从Web服务中获取大量数据项,然后可能需要获取更多数据项,然后再获取更多数据项,然后在完全需要后返回所有数据项。我不确定如何将其放入代码中。这是我的意思的一个例子:

  NSMutableArray * array = [[NSMutableArray alloc] init]; 

[webService getLatestItemsWithCount:50 completion:^(NSArray * objects){
//处理这些项目的一些代码。

if(moreItemsNeeded == YES){
//我现在需要它来循环这个块,直到我完成
}
}];

我怎样才能让它发挥作用?





好的,这就是我正在使用的 - 它是Evernote API。它应该是我需要的更好的例子:

  [noteStore findNotesMetadataWithFilter:filter 
offset:0
maxNotes:100
resultSpec:resultSpec
success:^(EDAMNotesMetadataList * metadataList){
for(EDAMNoteMetadata * metadataList.notes中的元数据){
NSDate * timestamp = [NSDate endateFromEDAMTimestamp :metadata.updated];

if(timestamp.timeIntervalSince1970> date.timeIntervalSince1970){
[array addObject:metadata];
}
else {
arrayComplete = YES;
}
}

//我需要它来循环这段代码,增加偏移量,直到数组完成。

}失败:^(NSError *错误){
NSLog(@失败:%@,错误);
}];


解决方案

您应该创建一个引用要生成的块的变量可能是递归调用。必须注意的是,在你分配块时,它仍然是 nil ,所以如果你在块本身(也就是递归)中调用它,你会在尝试执行时遇到崩溃 nil 块。所以块应该有* __ block *存储:

  void(^ __ block myBlock)(NSArray *)= ^(NSArray *对象){
//处理这些项目的一些代码。

if(moreItemsNeeded == YES){
//我现在需要它循环这个块直到我完成
myBlock(objects);
myBlock = nil; //避免保留周期
}
}];
[webService getLatestItemsWithCount:50 completion:myBlock];

特定情况下的区块被翻译为:

  void(^ __块处理程序)(EDAMNotesMetadataList)= ^(EDAMNotesMetadataList * metadataList){
for(EDAMNoteMetadata * metadataList.notes中的元数据){
NSDate * timestamp = [NSDate endateFromEDAMTimestamp:metadata.updated];

if(timestamp.timeIntervalSince1970> date.timeIntervalSince1970){
[array addObject:metadata];
}
else {
arrayComplete = YES;
}
}

//我需要它来循环这段代码,增加偏移量,直到数组完成。
if(!arrayComplete)
handler(metadataList);
handler = nil; //避免保留周期
};

然后您通常可以将 myBlock 作为参数调用该方法。



关于保留周期



为了避免保留周期,您应该设置为 nil 递归完成时指向块的指针。


I have some code which requires the use of blocks. The block fetches a number of data items from a web service, and then possibly needs to fetch more, and then more again after that, then returns all of the data items once it has all required. I'm unsure how to put this into code. Here's an example of what I mean:

NSMutableArray *array = [[NSMutableArray alloc] init];

[webService getLatestItemsWithCount:50 completion:^(NSArray *objects) {
    //Some code to deal with these items.

    if (moreItemsNeeded == YES) {
        //I now need it to loop this block until I'm done
    }
}];

How can I get this to work?

EDIT:

Ok, this is what i'm working with - it's the Evernote API. It should be a better example of what I need:

[noteStore findNotesMetadataWithFilter:filter
                                offset:0
                              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.

}failure:^(NSError *error) {
    NSLog(@"Failure: %@", error);
}];
解决方案

You should create a variable that references the block to make possible the recursive invocation. It must be noted that at the moment that you assign the block, it is still nil, so if you call it inside the block itself (aka recursively), you'll get a crash while trying to execute a nil block. So the block should have a *__block* storage:

void (^__block myBlock) (NSArray*) = ^(NSArray *objects) {
    //Some code to deal with these items.

    if (moreItemsNeeded == YES) {
        //I now need it to loop this block until I'm done
        myBlock(objects);
        myBlock= nil; // Avoid retain cycle
    }
}];
[webService getLatestItemsWithCount:50 completion: myBlock];

The block in your specific case is "translated" as this one:

void (^__block handler) (EDAMNotesMetadataList)= ^(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)
        handler(metadataList);
    handler= nil; // Avoid retain cycle
};

Then you can normally call that method passing myBlock as argument.

About retain cycles

To avoid a retain cycle, you should set to nil the pointer to the block when the recursion finishes.

这篇关于如何使用块处理循环代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-04 05:28