5

Tôi gặp sự cố khi nói đến phần phụ trợ chậm và tải xuống dữ liệu với cấu hình nền.NSURLSessionDownloadTask tiếp tục thử lại khi sử dụng Cấu hình nền

NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier]; 
_backgroundSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil]; 
NSURLSessionDownloadTask *downloadTask = [_backgroundSession downloadTaskWithURL:URL]; 
[downloadTask resume]; 

Nếu kết nối được thiết lập nhưng phải mất hơn 60 giây để kết nối gửi dữ liệu hết thời gian chờ. Điều đó là tốt. Tuy nhiên, hành vi mà tôi gặp phải là tôi không gặp lỗi. Phiên này chỉ gửi một yêu cầu mới. "Cung cấp lại dữ liệu cho tôi". Tôi không biết chuyện này xảy ra ở đâu. Không có trong mã của tôi và không có phương thức đại biểu nào được gọi là tôi biết. Tôi chỉ có quyền truy cập vào nhật ký máy chủ. Máy chủ mất khoảng 68 giây để gửi dữ liệu trở lại nhưng ứng dụng chỉ bỏ qua nó vì nó đang chờ yêu cầu mới.

Một giải pháp là tăng giá trị thời gian chờ. Nhưng tôi không thích nó và nó chỉ hoạt động cho iOS 7. Không phải iOS 8.

sessionConfig.timeoutIntervalForRequest = 10 * 60.0; 

Có ai có cái nhìn sâu sắc về điều này? Tôi tìm thấy số này link about timeout issue for background session tại đây trên stackoverflow. Đó là 10 tháng tuổi nhưng không có giải pháp, chỉ có những người đồng ý.

Trả lời

3

Tôi đã xoay xở để giải quyết. Tôi không nói giải pháp của mình là giải pháp nhưng đó là giải pháp một giải pháp.

Hành vi tôi gặp phải là iOS 7 và iOS 8 ưu tiên các thuộc tính khác nhau. Tôi có hai nơi để đặt các thuộc tính thời gian chờ này, NSURLSessionConfiguration và trong NSMutableURLRequest. iOS 7 không thể quan tâm đến tài sản yêu cầu và iOS 8 không thể quan tâm đến tài sản cấu hình. Ngay bây giờ giải pháp của tôi trông giống như sau:

NSURLSessionConfiguration *sessionConfig; 
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) { 
    sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:identifier]; 
} 
else { 
    sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier]; 
} 
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0) { 
    sessionConfig.timeoutIntervalForRequest = 5 * 60.0; 
} 
_backgroundSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil]; 

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; 
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) { 
    request.timeoutInterval = 5 * 60.0; 
} 
NSURLSessionDownloadTask *downloadTask = [_backgroundSession downloadTaskWithRequest:request]; 

Tôi đoán người ta không thể thực hiện kiểm tra systemVersion và đặt cả hai thuộc tính cho cùng một giá trị. Mặc dù tôi tin tưởng mạnh mẽ rằng ít mã hơn tôi tin rằng thậm chí còn mạnh mẽ hơn trong việc không ảnh hưởng đến các tiểu bang mà không cần phải bị ảnh hưởng. Tuy nhiên tôi rất muốn nghe ý kiến ​​của mọi người ý kiến ​​. Và nếu ai đó có giải pháp tốt hơn, vui lòng chia sẻ.

Ồ một điều nữa. Phần thử lại sẽ tiếp tục xảy ra cho đến khi timeoutIntervalForResource đạt giá trị mặc định là 7 ngày theo tài liệu. Tôi đã giảm xuống còn 10 phút.

sessionConfig.timeoutIntervalForResource = 10 * 60; 

Tôi không nói nó nên được thay đổi. Đây là một quyết định mà chúng tôi đã đưa ra cho thiết lập môi trường cụ thể của chúng tôi.

Cập nhật

Chúng tôi đã thay đổi timeoutIntervalForResource trở về giá trị mặc định là 7 ngày. Ví dụ, chúng tôi có khách hàng ở Trung Quốc và một số người trong số họ có kết nối thực sự kém. Một giới hạn tổng thể của 10 phút chỉ là ngớ ngẩn.

Đảm bảo xem Sunkas answer để có chất lượng mã tốt hơn. Đoạn mã của tôi, tuy nhiên, được trải ra trên các lớp khác nhau nên tôi không thể sử dụng lại phương pháp đó 100%.

+0

Câu hỏi: tại sao bạn phân biệt giữa iOS 8 và iOS 7 sau khi tất cả? Bạn không thể chỉ đặt cả timeoutIntervalForRequest và timeoutInterval? – dlinsin

6

Không thể dừng lại bản thân mình, đây là câu trả lời của bạn một chút refactored :)

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; 
NSURLSessionConfiguration *sessionConfig; 
float timeout = 5 * 60.0f; 

BOOL iOS8OrNewer = [[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0; 
if (iOS8OrNewer) { 
    sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:identifier]; 
    request.timeoutInterval = timeout; 
} 
else { 
    sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier]; 
    sessionConfig.timeoutIntervalForRequest = timeout; 
} 

_backgroundSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil]; 

NSURLSessionDownloadTask *downloadTask = [_backgroundSession downloadTaskWithRequest:request]; 
+2

Rất đẹp và dễ đọc, cảm ơn bạn! Mặc dù đoạn mã của tôi thực sự trải ra trên hai lớp riêng biệt nhưng tôi sẽ áp dụng những gì tôi có thể từ nó :) –

3

Kể từ iOS8, các NSUrlSession trong chế độ nền không gọi phương thức delegate này nếu máy chủ không đáp ứng. -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error Tải xuống/tải lên vẫn không hoạt động vô thời hạn. Đại biểu này được gọi trên iOS7 với lỗi khi máy chủ không phản hồi.

Nói chung, phiên nền NSURLSession không làm hỏng tác vụ nếu xảy ra sự cố trên dây. Thay vào đó, nó tiếp tục tìm kiếm một thời điểm tốt để chạy yêu cầu và thử lại tại thời điểm đó. Điều này tiếp tục cho đến khi hết thời gian chờ tài nguyên (nghĩa là giá trị của thuộc tính timeoutIntervalForResource trong đối tượng NSURLSessionConfiguration mà bạn sử dụng để tạo phiên). Giá trị mặc định hiện tại cho giá trị đó là một tuần! Nói cách khác, hành vi thất bại cho một thời gian chờ trong iOS7 là không chính xác. Trong bối cảnh của một phiên nền, nó là thú vị hơn để không thất bại ngay lập tức vì các vấn đề mạng. Vì vậy, kể từ iOS8, nhiệm vụ NSURLSession tiếp tục ngay cả khi nó gặp thời gian chờ và mất mạng. Nó tiếp tục tuy nhiên cho đến khi timeoutIntervalForResource đạt được.

Vì vậy, về cơ bản timeoutIntervalForRequest sẽ không hoạt động trong Phiên nền nhưng timeoutIntervalForResource sẽ.

Nguồn: Apple Forum

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