【问题标题】:IOS Use Single Dispatch_group Multiple Times in One ClassIOS在一个类中多次使用单个Dispatch_group
【发布时间】:2014-10-16 18:58:19
【问题描述】:

我有一个应用程序,该应用程序允许用户快速互相发送照片,但众所周知,用户并不总是拥有完美的互联网连接,因此我们决定创建一个系统,将所有照片临时存储在一个目录中以及字典数组中每个 api 请求的信息。如果用户拍摄 2 张​​照片要发送,而第一张照片由于没有连接而失败,然后几分钟后,当用户有互联网连接时拍摄了第三张照片,这就是发生的情况(伪),但我们会得到一些重复和奇怪如果队列开始备份并且整个过程被多次触发,就会发生这种情况。所以我们做了一些研究,dispatch_groups 似乎是答案,但我们无法弄清楚我们如何每次都使用相同的调度组,这样如果用户接受,就不会有多个调度组队列同时触发相同的请求20张照片真的很快。

该系统的另一个重要部分是它必须以相同的顺序上传所有图像,并且最好避免任何重复

-(void)upload:(NSString*)typeOfUpload{  

    [_resendBtn setHidden:YES];
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSMutableArray *pendingRequests=[[NSMutableArray alloc] init];

    NSString *pendingRequestsFrom= [NSString stringWithFormat:@"pendingRequestsForUid%@",[defaults objectForKey:@"uid"]];
    NSLog(@"PENDINGREQUESTFROM:%@",pendingRequestsFrom);


    if ([defaults objectForKey:pendingRequestsFrom]){
        pendingRequests= [[defaults objectForKey:pendingRequestsFrom]mutableCopy];
    }





    NSMutableDictionary *requestDict=[[NSMutableDictionary alloc] init];
    NSDate *now = [NSDate date];
    int timestamp = [[NSDate date] timeIntervalSince1970];
    [requestDict setObject:[NSString stringWithFormat:@"%d",timestamp] forKey:@"timestamp"];

    if(_convertedVideoURL){
        NSString*urlPath= [_convertedVideoURL path];
        [requestDict setObject:urlPath forKey:@"videoURL"];
    }

    if([typeOfUpload isEqualToString:@"PHOTO"]){

        // Get image data. Here you can use UIImagePNGRepresentation if you need transparency
        NSData *imageData = UIImageJPEGRepresentation(_imgToSend, 8);

        // Get image path in user's folder and store file with name image_CurrentTimestamp.jpg (see documentsPathForFileName below)

         //Create temporary URL to record to
         NSDate *now = [NSDate date];
         NSTimeInterval nowEpochSeconds = [now timeIntervalSince1970];
         NSString *intervalString = [NSString stringWithFormat:@"%f", nowEpochSeconds];

         NSString *main_img_path = [[NSString alloc] initWithFormat:@"%@image%@.jpg", NSTemporaryDirectory(), intervalString];

        // Write image data to user's folder
        [imageData writeToFile:main_img_path atomically:YES];



        [requestDict setObject:main_img_path forKey:@"imgToSendStored"];
    }
    [requestDict setObject:_selectedUserString forKey:@"recip_uid"];
    [requestDict setObject:typeOfUpload forKey:@"MEDIA_TYPE"];
    if([typeOfUpload isEqualToString:@"TEXT"]){
        [requestDict setObject:_textMsgView.coverCaption.text forKey:@"body"];
    }
    NSLog(@"params being stored for later %@", requestDict);
    [pendingRequests addObject:requestDict];



        NSArray *newArray= [NSArray arrayWithArray:pendingRequests];

    NSLog(@"TOTAL_PENDING_VIDS == %@, araay count == %d",newArray,[newArray count]);


    [defaults setObject:newArray forKey:pendingRequestsFrom];
    [defaults synchronize];
    _imgToSend=nil;
    _textToSend=nil;
    _isTextDropDownDisplayed=NO;
    [UIView animateWithDuration:.5 animations:^{

        [_textMsgView setFrame:CGRectMake(0, -300, 320, 10)];
        _textMsgView.coverCaption.text=@"";
        //secondView.alpha = 1.0;
        [self swippedAway];

    }];
    [self uploadStoredVidsFunction:@"UPLOAD"];
}



-(void)uploadStoredVidsFunction:(NSString*)typeOfResend
{



    NSString *pendingRequestsFrom= [NSString stringWithFormat:@"pendingRequestsForUid%@",[defaults objectForKey:@"uid"]];
    pendingRequests= [[defaults objectForKey:pendingRequestsFrom]mutableCopy];
    NSLog(@"PENDING_REQUESTS%@",pendingRequests);
    dispatch_group_t group = dispatch_group_create();
    for (int i=0;i<[pendingRequests count]; i++) {



         dispatch_group_enter(group);



        MAKE AFNETWORKING  REQUEST  

        success{
             remove request from pending array
           // start next request 
            dispatch_group_leave(group);

       } 
        failure {
            //STOP THE QUEUE from continuing to execute the rest of the requests in line/give user their options  ( aka  retry sending all/ delete all/save for later ) 
        }



}



}

【问题讨论】:

    标签: ios queue grand-central-dispatch afnetworking-2 dispatch


    【解决方案1】:

    您可以使用NSCondition 在未终止的while 循环中生成一个处理所有这些问题的新线程,以确保线程安全。

    // Somewhere in your initialization:
    requestLock = [[NSCondition alloc] init];
    [self performSelectorInBackground:@selector(processRequests)];
    
    - (void)processRequests {
      while (![[NSThread currentThread] isCancelled]) {
        [requestLock lock];
        if ([pendingRequests count] == 0 /* || delay time not yet reached */) {
          [requestLock waitUntilDate:someTimeoutDate];
          [requestLock unlock];
          continue;
        }
        NSMutableArray *remainingRequests = [pendingRequests copy];
        [pendingRequests removeAllObjects];
        [requestLock unlock];
        for (Request *request in requests) {
          if (success) {
            // Process the request and then..
            [remainingRequests removeObject:request];
          } else {
            break;
          }
        }
        [requestLock lock];
        [pendingRequests insertObjects:remainingRequests atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [remainingRequests count])]];
        [requestLock unlock];
      }
    }
    
    - (void)addRequest:(Request *)request {
      [requestLock lock];
      [pendingRequests addObject:request];
      [requestLock broadcast];
      [requestLock unlock];
    }
    

    【讨论】:

    • 首先感谢您的回复,但在我们的系统上,用户可以尽可能快地添加待处理的照片,因此第一个解决方案不会只有几个相同请求的队列进行和/或冒着请求乱序的风险,例如说我在pendingRequests中有5张图片,我清除了所有这些图片以尝试发送它们,同时又拍摄了5张并创建了一个新线程,线程一将尝试将请求添加回来首先进入索引为 0 到 5 的待处理请求,然后第二组将尝试在索引 0 到 5 处插入以 w 结尾的请求。 6,7,8,9,10,1,2,3,4,5?
    • 至于第二部分,我不太清楚什么是请求锁?
    • 第一个解决方案对您调用for 循环的频率做出了一些假设。如果您每次在队列中获得新项目时都调用它,而不管当前队列处理状态如何,那么是的,您将遇到问题。我猜你可以用BOOL 标志绕过它。 ;;; requestLock 是一个实例变量 NSCondition * 对象。除了确保您在修改 pendingRequests 的同时仍然尊重线程安全之外,它不会做任何事情。
    • 我更新了我的答案以删除最初的 dispatch_async 方法;为了确保您按顺序处理所有请求,您需要将它们放入一个队列中。
    • 在这个修订后的答案中,您是否假设所有这些都在主线程之外的它自己的线程中,如果不是这样“while (![[NSThread currentThread] isCancelled]) {"" 冻结主 ui 线程?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多