2014-10-16 53 views
0

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

该系统的另一个重要组成部分是,它必须必须在采取所有图像相同的顺序上传,因此最好避免重复

-(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)]; 
     [email protected]""; 
     //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) 
     } 



} 



} 

回答

2

你可以只产卵关闭一个新的线程,与所有优惠在一个未终结的while循环中使用NSCondition来确保线程安全。

// 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]; 
} 
+0

对于初学者感谢您的回复,但我们的系统上的用户可以添加快速未决的照片,因为他们可以挖掘这样难道不第一个解决方案只是有相同要求的几个队列会和/或有风险例如,我在pendingRequests中有5张图片,我清除所有这些以尝试发送它们,同时还有5个图片被创建,并且一个新的线程被创建,线程将尝试将请求添加回挂起首先在索引0到5处请求,然后第二组将尝试在索引0到5处插入结尾w。 6,7,8,9,10,1,2,3,4,5? – ChuckKelly 2014-10-16 20:04:29

+0

至于第二部分我不太清楚请求锁是什么? – ChuckKelly 2014-10-16 20:05:58

+0

第一个解决方案对你调用'for'循环的频率做了一些假设。如果每次在队列中获取新项目时调用它,而不管当前的队列处理状态如何,那么是的,您将遇到问题。我猜,你可以用'BOOL'标志来绕过它。 ;;; 'requestLock'是一个实例变量'NSCondition *'对象。除了确保在修改'pendingRequests'的同时仍然保持线程安全性以外,它什么也不做。 – 2014-10-16 20:10:27