【问题标题】:Incrementing a Variable from an Asynchronous Block in Objective-C在 Objective-C 中从异步块增加变量
【发布时间】:2018-09-13 20:00:18
【问题描述】:

我在 Objective-c 中从事的一项服务遇到了一些难题。该服务的目的是解析核心数据实体列表并为每个对象下载相应的图像文件。该服务的原始设计使我的网络服务器因过多的同时下载请求而窒息。为了解决这个问题,我将负责执行下载请求的代码移到了递归方法中。每个下载请求的完成处理程序都会再次调用该方法,从而确保每次下载都将等待前一个下载完成后再分派。

事情变得棘手的是负责实际更新我的核心数据模型和进度指示器视图的代码。在下载的完成处理程序中,在方法递归之前,我对负责更新核心数据的 a 块进行异步调用,然后更新视图以显示进度。该块需要有一个变量来跟踪该块已执行了多少次。在原始代码中,我可以简单地拥有一个块范围的方法级变量,该变量将在块内递增。由于该方法现在是递归的,因此该策略不再有效。方法级别变量将在每次递归时简单地重置。由于块调用的异步性质,我也不能简单地将变量传递到下一个级别。

我在这里完全不知所措。任何人都可以提出解决此问题的方法吗?

更新: 正如 matt 在下面指出的,这里的核心问题是如何控制请求的时间。在做了更多研究之后,我发现了为什么我的原始代码不起作用。事实证明,一旦启动第一个任务,超时间隔就开始运行,一旦时间到,任何额外的请求都会失败。如果您确切知道所有请求将花费多少时间,则可以简单地增加请求的超时时间。然而,更好的方法是使用 NSOperationQueue 来控制何时分派请求。有关如何执行此操作的一个很好的示例,请参见:https://code-examples.net/en/q/19c5248 如果您采用这种方法,请记住,您必须调用您在 downloadTask 的完成处理程序上创建的每个操作的 completeOperation() 方法。

一些示例代码:

-(void) downloadSkuImages:(NSArray *) imagesToDownload onComplete:(void (^)(BOOL update,NSError *error))onComplete
{
    [self runSerializedRequests:imagesToDownload progress:weakProgress downloaded:0 index:0 onComplete:onComplete ];
}

-(void)runSerializedRequests:(NSArray *) skuImages progress:(NSProgress *) progress downloaded:(int) totalDownloaded index:(NSUInteger) index onComplete:(void (^)(BOOL update,NSError *error))onComplete 
{
     int __block downloaded = totalDownloaded;

     TotalDownloadProgressBlock totalDownloadProgressBlock =  ^BOOL (SkuImageID *skuImageId, NSString  *imageFilePath, NSError *error) {
          if(error==nil) {
                  downloaded++;
                  weakProgress.completedUnitCount = downloaded;
                  //save change to core-data here
                  }
          else {
                        downloaded++;
                        weakProgress.completedUnitCount = downloaded;
                        [weakSelf setSyncOperationDetail:[NSString stringWithFormat:@"Problem downloading sku image %@",error.localizedDescription]];
                      }

          if(weakProgress.totalUnitCount==weakProgress.completedUnitCount) {
                              [weakSelf setSyncOperationIndicator:SYNC_INDICATOR_WORKING];
                              [weakSelf setSyncOperationDetail:@"All product images up to date"];
                              [weakSelf setSyncOperationStatus:SYNC_STATUS_SUCCESS];
                              weakProgress.totalUnitCount = 1;
                              weakProgress.completedUnitCount = 1;
                              onComplete(false,nil);
                              return true;
                          }
          return false;
     };

    NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:nil
    completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {

                NSLog(@"finished download %u of %lu", index +1, (unsigned long)skuImages.count);
                if(error != nil)
                {                    
                    NSLog(@"Download failed for URL: %@ with error: %@",skuImage.url, error.localizedDescription);
                }
                else
                {
                    NSLog(@"Download succeeded for URL: %@", skuImage.url);
                }
                dispatch_async(dispatch_get_main_queue(), ^(void){

                    totalDownloadProgressBlock(skuImageId, imageFilePath, error);

                });

                [self runSerializedRequests:manager skuImages:skuImages progress:progress downloaded:downloaded index:index+1 onComplete:onComplete ];
            }];

            NSLog(@"Starting download %u of %lu", index +1, (unsigned long)skuImages.count);
            [downloadTask resume];
}

【问题讨论】:

    标签: objective-c asynchronous scope objective-c-blocks


    【解决方案1】:

    该服务的原始设计使我的网络服务器因过多的同时下载请求而窒息。为了解决这个问题,我将负责执行下载请求的代码移到了递归方法中。

    但这从来都不是解决问题的正确方法。将单个持久自定义 NSURLSession 与您自己的配置一起使用,并设置配置的 httpMaximumConnectionsPerHost

    【讨论】:

    • 那我一定是遗漏了别的东西。我尝试使用该配置选项进行试验,但它实际上使事情变得更糟。据我所知,一旦达到限制,任何进一步的请求都会因超时而失败。
    • 好的,但在我看来,这仍然是一个 x-y 问题。你遇到了一个问题,而不是问这个问题,你假设一个不正确的解决方案,然后问为什么这个不正确的解决方案不起作用。它不起作用,因为它不正确。
    • 例如,很简单,您可以使用 NSOperation (Swift Operation) 来确保每次下载都在下一次开始之前完成。但是这里没有办法谈论这个,因为你问的是这个“递归”的东西。
    • 我认为你的方法是正确的。使用 NSOperations 可以让我解决底层问题(控制下载请求的时间),而不会出现递归方法引起的麻烦。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多