2013-09-23 66 views
6

Tôi đang sử dụng NSProgress để truyền đạt tiến độ tải xuống tệp trong ứng dụng iOS của tôi. Đây là một lớp học có mục đích chung và tôi hơi sợ sức mạnh vốn có của nó, đặc biệt là với hai thuộc tính xử lý hoàn thành. Có một để xử lý hủy bỏ, và một cho tạm dừng (nhưng không ai để hoàn thành, mà có lẽ là một hit ...)Với NSProgress, các trình xử lý hoàn thành có dành cho giao diện người dùng hoặc bộ điều khiển tải xuống không?

các trình xử lý này là gì? Mã thực hiện việc tải xuống có thể đặt logic trong các phương thức này để xử lý các yêu cầu hủy bỏ và tạm dừng do người dùng tạo. Tuy nhiên, không có gì ngăn cản một khách hàng ghi đè lên các trình xử lý bằng mã UI.

Vì vậy, nó dành cho giao diện người dùng? Tôi không chắc làm thế nào đây là một mô hình hữu ích, kể từ khi giao diện người dùng sẽ được bắt nguồn từ việc hủy bỏ hoặc tạm dừng anyway. Ngoài ra, nếu bạn đang sử dụng đối tượng tiến trình để đồng thời trình bày tiến trình trên nhiều phần tử giao diện người dùng (cách nó được sử dụng trong MacOS), các phần tử giao diện người dùng khác nhau có khả năng muốn xử lý hoàn thành của riêng nó.

Sử dụng trình xử lý để truyền đạt hành động của người dùng quay lại bộ điều khiển tải xuống có vẻ là mẫu hữu ích nhất, nhưng sau đó tôi đã mong đợi trình xử lý sẽ được thiết lập lúc khởi tạo và sau đó vẫn chỉ đọc.

Tôi thiếu gì ở đây?

(PS Để bây giờ tôi đang đơn giản là không sẽ sử dụng những bộ xử lý và dựa vào KVO. Tuy nhiên, tôi có một cảm giác ngứa mà tôi đang bỏ lỡ một số ý tưởng cơ bản đằng sau lớp)

+0

Trông giống như một lớp học riêng tư với tôi, bạn có chắc chắn muốn sử dụng nó không? – Ian

+1

Nó không phải là riêng tư. Xem [Tài liệu dành cho nhà phát triển của Apple] (https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSProgress_Class/Reference/Reference.html) –

+0

Tệ của tôi, tôi không có ý tưởng nào tồn tại. – Ian

Trả lời

1

Tôi tin rằng khóa mà bạn đang thiếu là lớp NSProgress được thiết kế để được sử dụng làm cây đối tượng tiến bộ. Hơn nữa cây này được tạo ra hoàn toàn với các đối tượng tiến bộ của trẻ em không cần phải biết rằng chúng được gắn với một phụ huynh, đây là nơi mà sức mạnh thực sự của nó xuất phát từ đó.

Tôi tìm thấy OS X Foundation Ghi chú phát hành nhiều hơn nữa hữu ích hơn so với tham chiếu lớp cho NSProgress:

https://developer.apple.com/library/Mac/releasenotes/Foundation/RN-Foundation/index.html

Lý do tại sao có vẻ như bộ xử lý có thể được sử dụng cho cả bộ điều khiển UI logic và điều khiển dữ liệu logic là khi bạn xây dựng một hệ thống phân cấp cha-con, bạn có hai bộ xử lý có thể được sử dụng cho cả hai. Trình xử lý của cha mẹ sẽ được đặt ở cấp điều khiển giao diện người dùng ('người tiêu dùng' của tiến trình) và các trình xử lý của trẻ sẽ được đặt bởi bộ điều khiển dữ liệu ('nhà cung cấp').

Vì mối quan hệ có thể được tạo ra hoàn toàn bằng cách sử dụng becomeCurrentWithPendingUnitCount: đối tượng tiến bộ của trẻ sẽ được cách ly với cha mẹ, điều này sẽ làm giảm bớt lo ngại của bạn về khách hàng ghi đè bất kỳ trình xử lý cấp dữ liệu nào.

Gọi pause hoặc cancel trên đối tượng tiến trình sẽ truyền bá cuộc gọi đó xuống cây, gọi bất kỳ trình xử lý nào đang xử lý.

Một ví dụ:

// UI controller level, probably a UIViewController subclass. 
- (void)handleDoSomethingButtonTapped:(UIButton *)sender 
{ 
    self.progressThatWeObserve = 
     [NSProgress progressWithTotalUnitCount:100]; // 100 is arbitrary 
    self.progressThatWeObserve.pausingHandler = ^{ 
     // Update UI, reflect paused state ... 
    }; 

    [self.progressThatWeObserve becomeCurrentWithPendingUnitCount:100]; 
    [self.dataController doSomethingInBackgroundWithCompletionHandler:^{ 
     // Update UI, remove from view ... 
    }]; 
    [self.progressThatWeObserve resignCurrent]; 
} 

// Data controller level, a SomethingManager class maybe. 
- (void)doSomethingInBackgroundWithCompletionHandler:(void (^)(void)completionHandler 
{ 
    self.progressThatWeManipulate = 
     [NSProgress progressWithTotalUnitCount:289234]; // e.g. bytes to upload 
    self.progressThatWeManipulate.pausingHandler = ^{ 
     // Actually suspend the network operation ... 
    }; 

    dispath_async(self.workerQueue, ^{ 
     // Periodically update progress 
    }); 
} 

Xin lưu ý tôi đã không thực sự thực hiện bất kỳ điều này, đó là tất cả lý thuyết từ việc đọc tài liệu.

0

Bạn có thể sử dụng những khối cho bất cứ điều gì bạn muốn. Cụ thể, nếu bạn muốn làm điều gì đó với giao diện người dùng, bạn nên đảm bảo thực hiện điều đó trên luồng chính như được lưu ý trong phần "xem xét đặc biệt" của tài liệu "Trình xử lý hủy có thể được gọi trên bất kỳ hàng đợi nào. làm việc trên một hàng đợi cụ thể, bạn nên gửi đến hàng đợi đó từ bên trong khối xử lý hủy. " Vì vậy, đối UI bạn sẽ sử dụng:

dispatch_async(dispatch_get_main_queue(), ^{ 
    // Do work on UI 
}); 

Các mô hình xử lý hoàn thành được phổ biến để đối phó với nhiệm vụ được 'always' thực hiện trong nền; Các nhiệm vụ I/O như tải xuống tệp từ máy chủ. Trong trường hợp này, mặc dù cũng hữu ích khi xác định một trình xử lý đơn để tạm dừng và hủy vì có thể có nhiều sự kiện trong ứng dụng của bạn gọi phương thức pause: or cancel: trên cá thể NSProgress.

+0

Đó là một thực tế là tôi * có thể * sử dụng chúng cho bất cứ điều gì tôi muốn mà confuses tôi. Tuy nhiên, tôi nghĩ rằng bạn là chính xác trong đó vì đây là những khối có khả năng sẽ được gọi là trong nền, họ không có ý định cho mã UI. Tức là, mã logic tải xuống sẽ đặt các trình xử lý và mã giao diện người dùng sẽ không bao giờ gây rối với các trình xử lý đó. –

+0

Phải, vì vậy nếu bạn muốn thực hiện công việc trên giao diện người dùng trong các khối đó, bạn nên đặt nó trên chuỗi chính (nơi duy nhất bạn nên xáo trộn với giao diện người dùng), như trong câu trả lời của tôi. – JuJoDi