objective-c - 如果我有一个使用 Obj-C block 的 for 循环,我如何识别最后一次迭代?

标签 objective-c asynchronous objective-c-blocks

我有一个简单的类,它公开了一个方法,该方法进行多个服务器调用以获取对象 ID 列表的对象数据。该方法枚举对象 ID 列表并进行单独的服务器调用,如下所示...

@implementation MyClass

- (void)fetchObjectsFromServerWithObjectIDs:(NSArray*)objectIDs {

    typeof(self) __weak blockSelf = self;
    for(NSString *objectID in objectIDs) {
        [self fetchObjectDataForObjectID:objectID withSuccessBlock:^{
            if(objectID == [objectIDs lastObject]) {  //<---will this work?
                [blockSelf.delegate finishedFetching]; 
            }
        }];
    }
}

- (void)fetchObjectDataForObjectID:(NSString*)objectID
                  withSuccessBlock:(void (^)())successBlock {

    void (^successWrapperBlock)(void) = ^{

        //Some processing of returned data is done here

        if(successBlock) {
            successBlock();
        }
    };

    [HTTPClient fetchObjectDataWithObjectID:objectID
                            withSuccessBlock:successWrapperBlock
                                failureBlock:nil];
}

@end

...我正在尝试找出检查最后一个 successBlock 是否正在执行的最佳方法,以便我可以告诉代理它已完成获取数据。我在代码中有一条评论“<---这行得通吗?”标记正在执行检查的语句,但我觉得它不安全,因为该 block 是异步的,并且 if(objectID == [objectIDs lastObject]) 在执行第一个 successBock 时可能为真。

如何确定最后一个 successBlock 何时被执行?预先感谢您的智慧!

最佳答案

指针比较 (objectID == [objectIDs lastObject]) 在这里没问题,因为如果数组未修改,您将获得相同的对象。如果您担心 objectIDs 可能会被修改(例如,它可能实际上是一个可变数组并在另一个线程上被修改或通过沿途的通知等副作用),最好的保护是复制开头的数组:

- (void)fetchObjectsFromServerWithObjectIDs:(NSArray*)objectIDs {

    typeof(self) __weak blockSelf = self;
    NSArray *copiedIDs = [objectIDs copy];

    for(NSString *objectID in copiedIDs) {
        [self fetchObjectDataForObjectID:objectID withSuccessBlock:^{
            if(objectID == [copiedIDs lastObject]) {
                [blockSelf.delegate finishedFetching]; 
            }
        }];
    }
}

现在有两种调用委托(delegate)的方法:

  1. 最后一次提取完成后调用它。
  2. 或者在最后一个对象的提取完成后调用它,即使其他提取请求正在进行中也是如此。

所以你可以:

  • 使用@ChrisH 建议的计数器。这将在最后一次提取完成后调用委托(delegate),无论它们的处理顺序如何。
  • 使用指针比较。这将在 lastObject 的提取完成后调用委托(delegate)。
    • 为此,我认为您可以进行一些小的优化。实际上,它的缺点是它会捕获 block 中的数组并在每次调用 block 时调用不必要的方法调用。相反,您可以将最后一个对象保存在一个变量中,以便 block 捕获最后一个对象而不是整个数组。请注意,按 block 捕获数组不会造成任何损害。它可能只是推迟释放一些内存。

所以你可以这样做(@ChrisH 的版本加上 copy):

- (void)fetchObjectsFromServerWithObjectIDs:(NSArray*)objectIDs {

    typeof(self) __weak blockSelf = self;
    NSArray *copiedIDs = [objectIDs copy];
    __block NSUInteger count = [copiedIDs count];

    for(NSString *objectID in copiedIDs) {
        [self fetchObjectDataForObjectID:objectID withSuccessBlock:^{
            if(--count == 0) {
                [blockSelf.delegate finishedFetching]; 
            }
        }];
    }
}

或:

- (void)fetchObjectsFromServerWithObjectIDs:(NSArray*)objectIDs {

    typeof(self) __weak blockSelf = self;
    NSArray *copiedIDs = [objectIDs copy];
    id lastObject = [copiedID lastObject];

    for(NSString *objectID in copiedIDs) {
        [self fetchObjectDataForObjectID:objectID withSuccessBlock:^{
            if(objectID == lastObject) {
                [blockSelf.delegate finishedFetching]; 
            }
        }];
    }
}

关于objective-c - 如果我有一个使用 Obj-C block 的 for 循环,我如何识别最后一次迭代?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20316587/

相关文章:

iphone - UIActionSheet 着色

iphone - 更改 UIView 的图层类

Node.js Web 服务器 fs.createReadStream 与 fs.readFile?

objective-c - Objective C block - 语法

ios - Objective C block 泛型

ios - 从 Twitter 帐户 block 返回 nsmutablearray

ios - 如何检查 "Allow Full Access"自 iOS 8.3 *从容器应用程序*被授予

iphone - 如何在 UIImage 中只显示图像的一部分?

asynchronous - Rust 异步程序中的性能和内存问题

c# - 等待任务完成而不阻塞 UI 线程