如果我有一个使用Obj-C块的for循环,该如何确定最后一次迭代?

 或许就是一场梦_913 发布于 2023-02-13 15:35

我有一个简单的类,它公开了一种方法,该方法进行多个服务器调用以获取对象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是否正在执行的最佳方法,以便我可以告诉委托人它已完成数据的获取。我在代码“ <---这项工作会吗?”中有评论。标记正在执行检查的语句,但对我来说并不安全,因为该块是异步的,并且if(objectID == [objectIDs lastObject])在执行第一个successBock时可能为true。

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

1 个回答
  • 这里的指针比较(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]; 
                }
            }];
        }
    }
    

    现在有两种方法可以调用该委托:

      最后一次提取完成后,调用它

      在最后一个对象提取完成后调用它,即使正在进行其他提取请求。

    这样你就可以:

    使用类似@ChrisH建议的计数器。在最后一次提取完成后,无论处理顺序如何,都将调用委托。

    使用指针比较。对lastObject的获取完成后,将调用委托。

    为此,我认为您可以做一个小的优化。就其本身而言,它的缺点是它会捕获块中的数组,并在每次调用该块时调用不必要的方法调用。相反,您可以将最后一个对象保存在变量中,以便该块捕获最后一个对象而不是整个数组。请注意,通过块捕获数组不会造成任何伤害。它可能只是推迟释放一些内存。

    因此,您可以这样做(@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]; 
                }
            }];
        }
    }
    

    2023-02-13 15:38 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有