5

Tôi phải đồng bộ hóa một loạt thông tin từ RestAPI của mình. Tôi phải làm 6 cuộc gọi RestAPI để hoàn thành công việc. Tôi đã thiết kế các cuộc gọi API với Blocks và trả về NSError nếu có. 3 trong số các cuộc gọi này nên thực thi lồng nhau vì cuộc gọi đầu tiên cung cấp thông tin cho người khác và cho phép thực hiện trong khi 3 cuộc gọi khác có thể chạy độc lập. Do cải thiện hiệu suất mạng, tôi đã thiết kế cuộc gọi đồng bộ hóa của mình như sau:NSBlockOperation, NSOperationQueue và Blocks

  • 1 NSBlockOperation có chứa 3 khối lồng nhau đầu tiên;
  • 1 NSBlockOperation có chứa ba khối khác;
  • 1 NSBlockOperation mà tôi sử dụng làm "semphore" và cho tôi biết khi nào tất cả công việc đã hoàn thành.

NSBlockOperation cuối cùng có sự phụ thuộc vào hai NSBlockOperation trước đó.

Tôi cũng có NSOperationQueue chứa tất cả ba NSBlockOperation trong đó NSBlockOperation semaphore được thêm vào cuối cùng trong hàng đợi. Kết quả mà tôi sẽ đạt được là: hai khối đầu tiên được gọi là Đồng thời và khi kết thúc công việc của chúng, NSBlockOperation semaphore được gọi và trả về các điều khiển cho Người dùng cung cấp UIAlertMessage.

Kết quả không được giải thích trước đó: các điều khiển được trả về mà không cần chờ đến cuối khối syncAllBlocksInformation.

Bên dưới mã có chứa NSBlockOperation:

-(void)syncAllBlocksInformation:(void(^)(NSError *error))completion{ 

__block NSError *blockError = nil; 

NSOperation *syncUserInfoOperation = [NSBlockOperation blockOperationWithBlock:^{ 
    [dataSync syncUserInfo:tfMail.text password:tfPassword.text completion:^(NSError *error, NSNumber *idUser) { 
     if(!error){ 
      [dataSync syncUserfilesInfo:idUser completion:^(NSError *error) { 
       if(!error){ 
        [dataSync syncUserBookings:^(NSError *error) { 
         if(error){ 
          blockError = error; 
         } 
        }]; 
       } 
       else{ 
        blockError = error; 
       } 
      }]; 

     } 
     else{ 
      blockError = error; 
     } 
    }]; 
}]; 



NSBlockOperation *otherSyncOperations = [NSBlockOperation blockOperationWithBlock:^{ 
    [dataSync syncNewsInfo:^(NSError *error) { 
     if(error){ 
      blockError = error; 
      NSLog(@"error %@",error); 
     } 
    }]; 

}]; 

[otherSyncOperations addExecutionBlock:^{ 
    [dataSync syncLocationsInfo:^(NSError *error) { 
     if(error){ 
      blockError = error; 
      NSLog(@"error %@",error); 
     } 
    }]; 

}]; 

[otherSyncOperations addExecutionBlock:^{ 
    [dataSync syncExoticAnimalTypesAndAnimals:^(NSError *error) { 
     if(error){ 
      blockError = error; 
      NSLog(@"error %@",error); 
     } 
    }]; 
}]; 


NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{ 
    NSLog(@"END"); 
}]; 

[completionOperation setCompletionBlock:^{ 
    NSLog(@"Syc isEx %i",syncUserInfoOperation.isExecuting); 
    NSLog(@"other isEx %i",otherSyncOperations.isExecuting); 
    completion(blockError); 
}]; 

NSOperationQueue *opQueue = [NSOperationQueue new]; 

[completionOperation addDependency:syncUserInfoOperation]; 
[completionOperation addDependency:otherSyncOperations]; 

[opQueue addOperation:syncUserInfoOperation]; 
[opQueue addOperation:otherSyncOperations]; 
[opQueue addOperation:completionOperation]; 

} 

Và đây, mã mà các cuộc gọi trên khối:

-(IBAction)login:(id)sender{ 

[self dismissKeyboardOpened:nil]; 

hud=[MBProgressHUD showHUDAddedTo:self.view animated:YES]; 
[hud setLabelText:NSLocalizedString(@"login_hud_message", login_hud_message)]; 
[hud setMode:MBProgressHUDModeIndeterminate]; 

[self showHudAndNetworkActivity:YES]; 

[self syncAllBlocksInformation:^(NSError *error) { 

    [self showHudAndNetworkActivity:NO]; 

    if(!error){ 
     NSLog(@"End LOGIN"); 
     [self showAlert:@"Login" message:@"Login OK" dismiss:YES]; 
    } 
    else{ 
     [self showAlert:@"Error" message:@"Login NO" dismiss:NO]; 
    } 

}]; 
} 

Có chuyện gì vậy?

+0

Bạn đã cố gắng thực hiện 'NSOperationQueue' một biến mẫu của lớp bao quanh? –

+0

Tôi đã làm. Tôi đã khai báo là biến mẫu và tôi đã khởi tạo nó trong ViewDidLoad. Không có gì thay đổi. – dpizzuto

Trả lời

3

Vấn đề là NSBlockOperation là dành cho đồng bộ khối. Nó sẽ là finished ngay sau khi (các) khối của nó đã hoàn thành việc thực thi. Nếu (các) khối của nó kích hoạt các phương pháp không đồng bộ, các khối đó sẽ chạy độc lập.

Ví dụ: khi khối syncUserInfoOperation của bạn được thực thi, nó sẽ tắt [dataSync syncUserInfo:...] và sau đó tự xem là đã hoàn tất; nó không đợi cho bất kỳ người xử lý hoàn thành nào bắn, hoặc bất cứ thứ gì như thế.

Một giải pháp tốt cho việc này là tạo các lớp con của riêng bạn NSOperation. Bạn có thể muốn tạo một loại cho từng loại đồng bộ hóa dữ liệu của mình để dễ dàng hơn trong việc thiết lập các phụ thuộc, v.v., nhưng điều đó tùy thuộc vào bạn. Bạn có thể đọc tất cả về cách làm điều đó here (hãy nhớ đọc phần "Configuring Operations for Concurrent Execution").

Bạn cũng có thể tạo một lớp con chung NSOperation có một khối có thể chạy không đồng bộ. Vấn đề chính với nó là nó làm cho nó khó khăn hơn để xử lý những thứ như hủy bỏ các hoạt động, mà bạn có thể vẫn muốn.

+0

tôi đã tìm ra rằng chỉ có giải pháp khả thi là để phân lớp NSOperation và quản lý bằng tay hai loại khối không đồng bộ nhưng tôi nghĩ là có một "ánh sáng" giải pháp. Tôi đánh dấu là hợp lệ câu trả lời của bạn và càng sớm càng tốt, tôi sẽ đăng bài thực hiện của tôi. Thx – dpizzuto

+0

Một giải pháp "nhẹ" có thể được sử dụng [hàng đợi công văn Grand Central Dispatch của] (https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW1) ('NSOperation' và gia đình sử dụng những trong việc thực hiện). Cùng với các chức năng tạo hàng đợi và gửi đến chúng, bạn cũng muốn xem xét các nhóm công văn để quản lý sự phụ thuộc của bạn. Công văn hàng đợi là rất mạnh mẽ và ánh sáng, nhưng bạn sẽ mất một số chức năng tốt đẹp được xây dựng trong 'NSOperation'. –

Các vấn đề liên quan