2013-05-15 18 views
10

Tôi dường như có một số nhầm lẫn giữa các hàng đợi dispatch_queue_tNSOperationQueue.Nhận dispatch_queue_t cơ bản từ NSOperationQueue

Theo mặc định, AFImageRequestOperation của AFNetworking sẽ thực thi khối gọi lại thành công trên chuỗi chính của ứng dụng. Để thay đổi điều này, AFHTTPRequestOperation có thuộc tính successCallbackQueue cho phép bạn chọn hàng đợi để chạy cuộc gọi lại.

Tôi đang cố gắng thực hiện cuộc gọi lại thành công trên cùng một chuỗi nền/chủ đề nền đã thực hiện yêu cầu HTTP. Thay vì trở về chủ đề chính, NSOperationQueue chạy yêu cầu HTTP cũng sẽ chạy cuộc gọi lại vì có một số phép tính nặng mà tôi cần thực hiện bằng cách sử dụng một số hình ảnh đã trả về.

Lần thử đầu tiên của tôi là đặt successCallbackQueue thành ví dụ NSOperationQueue mà trên đó AFImageRequestOperation chạy. Tuy nhiên, thuộc tính successCallbackQueue thuộc loại dispatch_queue_t, vì vậy tôi cần một cách để có được cơ bản dispatch_queue_t trong số NSOperation ví dụ của mình, nếu có một thứ như vậy.

Điều đó có thể xảy ra hay tôi cần tạo riêng dispatch_queue_t?

Lý do tôi hỏi: Hơi lạ khi AFNetworking kế thừa từ NSOperation, nhưng hy vọng chúng tôi sử dụng hàng đợi dispatch_queue_t cho các cuộc gọi lại. Loại trộn hai mô hình dispatch_queue_tNSOperationQueue.

Cảm ơn mọi gợi ý!

Trả lời

8

Không có những điều như vậy, không phải là một one-to- tương ứng của một số NSOperationQueuedispatch_queue_t, các khái niệm xếp hàng trong hai API rất khác nhau (ví dụ: NSOperationQueue không có hàng đợi FIFO nghiêm ngặt như GCD).

Hàng đợi công văn duy nhất được NSOperationQueue sử dụng để thực thi mã của bạn là hàng đợi đồng thời toàn cầu ưu tiên mặc định.

+0

Khá chắc chắn điều này không đúng trong năm 2013, nhưng chắc chắn Yosemite NSOperationQueue có thuộc tính 'innerQueue' hiển thị 1: 1 tương ứng. –

+0

không, không hoàn toàn, thuộc tính đó chỉ là không-nil nếu bạn có 'setUnderlyingQueue:' trước đó ... nếu không có một hàng đợi công văn mới được thực hiện theo yêu cầu cho mỗi lần thực thi NSOperation. Trong bất kỳ trường hợp nào, các hàng đợi gửi đi vẫn chỉ được sử dụng để thực hiện, hàng đợi của NSOperationQueue vẫn hoàn toàn tách biệt và chỉ khi NSOperationQueue xác định một hoạt động sẽ được chạy, nó sẽ được thêm vào hàng đợi công văn để thực thi. – das

+0

Tôi không thấy cách này trả lời câu hỏi. Câu hỏi đặt ra là, làm thế nào để bạn có được AFNetworking gọi lại cho bạn trên cùng một chuỗi nơi bạn gọi nó. Câu trả lời bạn có thể không? Hoặc bạn phải tạo một hàng đợi công văn riêng biệt? –

3

Điều thú vị là AFHTTPClient sử dụng NSOperationQueue để chạy AFHTTPRequestOperations nhưng GCD dispatch_queues để xử lý kết quả.

Về tài liệu NSOperationQueue Apple nói:

Lưu ý: Trong iOS 4 và sau đó, hàng đợi hoạt động sử dụng Grand Central Dispatch để thực hiện các hoạt động.

nhưng dường như không có API công khai để nhận dispatch_queue cho một hoạt động nhất định.

Nếu nó không phải là quan trọng với bạn rằng callback thành công phải được trên chính xác cùng một hàng đợi/thread rằng hoạt động ban đầu đã được thực hiện tại sao không thiết lập:

successCallbackQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0); 
+0

Cảm ơn, tôi sẽ làm điều đó cho đến khi có thể ai đó có lựa chọn tốt hơn. – cheeesus

+0

Vâng, không thực sự là một câu trả lời như vậy là nó? Xin lỗi :) –

+0

Không có vấn đề gì, tham khảo tốt cho bất kỳ ai có câu hỏi tương tự :) – cheeesus

1

Trước hết, đó là một hành vi tốt để thực hiện thành công của chuỗi AFImageRequestOperation trên chủ đề chính vì cách sử dụng chính của thao tác này là tải xuống hình ảnh ở chế độ nền và hiển thị hình ảnh trên giao diện người dùng (phải nằm trên chuỗi chính), nhưng để đáp ứng nhu cầu của người dùng (trường hợp của bạn quá), những người muốn thực hiện cuộc gọi lại trên các chủ đề khác, cũng có một successCalbackQueue.

Vì vậy, bạn có thể tạo dispatch_queue_t của riêng mình với phương thức dispatch_queue_create hoặc cách được đề xuất, bạn nên sử dụng dispatch_get_global_queue để nhận hàng đợi chính.

Trên mỗi trường hợp, hãy chắc chắn rằng trong khối thành công của bạn, nếu bạn đang làm cho một số thay đổi đối với giao diện người dùng, đặt chúng bên trong dispatch_async(dispatch_get_main_queue(), ^{ // main op here});

+0

Nó chỉ là một hành vi tốt nếu bạn muốn làm một cái gì đó liên quan đến giao diện người dùng. Nếu bạn muốn làm một công việc rất nặng (như lọc hình ảnh hoặc phát hiện khuôn mặt) thì đó là một hành vi xấu. – Ricardo

+0

Để echo @Ricardo nó thực sự là rất phổ biến để phải làm một số lượng chế biến trên dữ liệu đáp ứng theo đó nó là không thích hợp để đổ này vào chủ đề chính. – amcc

5

NSOperationQueue không phải là nút cổ chai của bạn với AFNetworking. Yêu cầu hoạt động bị ràng buộc bởi mạng, không phải CPU hoặc bộ nhớ. Tất cả công việc được thực hiện không đồng bộ trong hàng đợi công văn, có thể truy cập dưới dạng thuộc tính trong AFHTTPRequestOperation.

Không nên sử dụng chuỗi mạng để thực hiện bất kỳ quá trình xử lý nào. Điều này sẽ không cải thiện hiệu suất theo bất kỳ cách nào. Thay vào đó, nếu bạn nhận thấy các vấn đề về hiệu suất, hãy thử giới hạn số lượng hoạt động đồng thời tối đa trong hàng đợi hoạt động, như một cách để kiểm soát gián tiếp lượng công việc đang được thực hiện bởi các hàng đợi xử lý nền đó.

3

XCode 6.4 dành cho iOS 8.4, ARC kích hoạt

1) "... vì vậy tôi cần một cách để có được những dispatch_queue_t cơ bản của dụ NSOperation của tôi, nếu có một điều như vậy."

Có một tài sản của NSOperationQueue có thể giúp:

@property(assign) dispatch_queue_t underlyingQueue 

Nó có thể được sử dụng như sau để gán cho NSOperationQueue:

NSOperationQueue *concurrentQueueForServerCommunication = [[NSOperationQueue alloc] init]; 
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
    concurrentQueueForServerCommunication.underlyingQueue = concurrentQueue; 

Hoặc gán từ NSOperationQueue:

NSOperationQueue *concurrentQueueForServerCommunication = [[NSOperationQueue alloc] init]; 
dispatch_queue_t concurrentQueue = concurrentQueueForServerCommunication.underlyingQueue; 

Không chắc liệu API bạn đang sử dụng cho mạng thông tin dữ cập nhật giao diện người dùng của bạn sau khi hoàn thành nhiệm vụ mạng, nhưng chỉ trong trường hợp nó không, sau đó bạn phải biết để có được trở lại hàng đợi chính khi khối hoàn thành được thực hiện:

dispatch_sync(dispatch_get_main_queue(), ^{ 

//Update your UI here... 

} 

Hope this helps! Chúc mừng.

+0

Đây sẽ là câu trả lời chính xác ngay bây giờ. –

+0

@MarkoNikolovski Cảm ơn Marko, rất vui vì tôi có thể giúp đỡ. Hy vọng rằng đủ người nhận thấy điều này cho OP để đánh dấu câu trả lời của tôi là chính xác. –

0

Swift 3 mã, dựa trên câu trả lời @ serge-k của:

// Initialize the operation queue. 
let operationQueue = OperationQueue() 
operationQueue.name = "com.example.myOperationQueue" 
operationQueue.qualityOfService = .userInitiated 

// Initialize a backing DispatchQueue so we can reuse it for network operations. 
// Because no additional info is give, the dispatch queue will have the same QoS as the operation queue. 
let operationQueueUnderlyingQueue = DispatchQueue(label: "com.example.underlyingQueue") 
operationQueue.qualityOfService.underlyingQueue = operationQueueUnderlyingQueue 

Sau đó bạn có thể sử dụng trong Alamofire (hoặc AFNetworking) theo cách sau đây:

Alamofire.request("https://example.com/get", parameters: nil).validate().responseJSON(queue: operationQueue.underlyingQueue) { response in 
    response handler code 
} 

Phạt cảnh cáo ở đây, từ tài liệu của Apple về cách đặt hàng đợi cơ bản của OperationQueue:

Giá trị của thuộc tính này chỉ nên được thiết lập nếu không có hoạt động nào trong hàng đợi; đặt giá trị của thuộc tính này khi operationCount không bằng 0 làm tăng số invalidArgumentException.Giá trị của thuộc tính này không được là giá trị được trả về bởi dispatch_get_main_queue(). Mức chất lượng dịch vụ được đặt cho hàng đợi công văn cơ bản ghi đè bất kỳ giá trị nào được đặt cho thuộc tính qualityOfService của hàng đợi hoạt động.