2015-05-14 15 views
5

Tôi đang tạo một completionHandler trả về một từ điển nhưng khi tôi gọi phương thức này trong một lớp khác giá trị của nó là không.Lưu trữ các giá trị trong hoàn thànhHandlers - Swift

func fetchLatestPosts(completionHandler: (responseDict: NSDictionary) -> Void in { 
// Bunch of JSON Parsing for dictionary to be completed 
var theDictionary = JSON Dictionary value 
responseDict = theDictionary as NSDictionary 
} 

Sau đó, tôi đang cố gọi nó trong lớp khác để có thể xem giá trị và dữ liệu được trình bày dựa trên điều đó. Ví dụ,

func parseDictionary() { 
NetworkManager.sharedInstance.fetchLatestPosts(responseDict: NSDictionary) 
if (responseDict != nil) { 
println("Dictionary is not empty") 
} 

Vấn đề ở đây là khi tôi gọi fetchLatestPosts chức năng Tôi nhận được một giá trị nil khi cố gắng gọi từ điển.

Tóm lại, câu hỏi của tôi là làm cách nào để gán giá trị cho trình xử lý hoàn thành được lưu trữ và có thể được gọi ở nơi khác trong dự án Xcode?

Trả lời

6

Câu hỏi của bạn bị cắt xén. Mã mẫu của bạn không hợp lệ và không hiển thị trình xử lý hoàn thành đang được sử dụng.

Tôi nghi ngờ bạn hiểu sai cách yêu cầu đồng bộ hóa và trình xử lý hoàn thành hoạt động. Đây là trình tự.

  1. Gọi một hàm và cung cấp một bộ xử lý hoàn
  2. Chức năng trả về ngay lập tức, và tại một thời điểm trong tương lai con chạy theo yêu cầu
  3. Dòng tiếp theo sau khi xử lý xong chạy trước khi yêu cầu thậm chí bắt đầu chế biến. Ứng dụng của bạn tiếp tục chạy. Không có kết quả nào vì yêu cầu chưa hoàn thành.
  4. Yêu cầu không đồng bộ cuối cùng cũng kết thúc. phương thức gốc gọi trình xử lý hoàn tất. NGAY BÂY GIỜ kết quả có sẵn, trong mã trong trình xử lý hoàn thành. Mã xử lý hoàn thành thực hiện mọi thứ cần thiết để xử lý các kết quả.

Dưới đây là một ví dụ thực tế như thế nào một quá trình async với xử lý hoàn có thể làm việc: (Bạn có thể tìm thấy một dự án Xcode làm việc thể hiện mã này trên Github tại this link)

Lần đầu tiên một AsyncManager lớp mô phỏng tải hình ảnh từ internet:

class AsyncManager 
{ 
    static let sharedAsyncManager = AsyncManager() 

    func asyncFetchImage(#imageName: String, completion: (image: UIImage?, status: String) ->()) 
    { 
    println("Entering \(__FUNCTION__)") 

    //Simulate a network operation by waiting 3 seconds before loading an image 
    let nSecDispatchTime = dispatch_time(DISPATCH_TIME_NOW, 
     Int64(3.0 * Double(NSEC_PER_SEC))) 
    let queue = dispatch_get_main_queue() 
    dispatch_after(nSecDispatchTime, queue) 
     { 
     () -> Void in 
     let result = UIImage(named: imageName) 
     println("Loading image in background") 
     let status = result != nil ? "image loaded" : "Error loading image" 
     println("About to call completion handler") 
     completion(image: result, status: status) 
    } 
    println("Leaving \(__FUNCTION__)") 
    } 
} 

Đây là một đơn. Nó có một sharedAsyncManager cho phép bạn sử dụng để tìm nạp một cá thể của AsyncManager.

AsyncManager cung cấp một phương thức, asyncFetchImage, có tên hình ảnh và khối hoàn thành. Hàm này không trả về bất kỳ kết quả nào, vì nó trả về ngay lập tức, trước khi tải hình ảnh diễn ra.

Mã không thực sự tải xuống hình ảnh từ internet. Thay vào đó nó chỉ đơn giản là sử dụng cuộc gọi GCD dispatch_after để chờ 3 giây trước khi tải một hình ảnh và gọi khối hoàn thành.

Bây giờ tôi tạo một lớp ViewController và cung cấp cho nó một nút "Load Image". Tôi tạo một IBOutlettheImageView đến UIImageView sẽ hiển thị hình ảnh tôi sẽ tải.

Tôi viết phương thức IBAction cho nút Tải hình ảnh.Dưới đây là những gì mà IBAction trông giống như:

@IBAction func loadImage(sender: UIButton) 
{ 
    let theAsyncManager = AsyncManager.sharedAsyncManager 
    println("about to call asyncFetchImage") 
    theAsyncManager.asyncFetchImage(imageName: "wareto_blue_150x115") 
    { 
     (image, status) ->() in 
     println("Beginning completion block") 
     self.theImageView.image = image 
     println("In completion block, status = \(status)") 
    } 
    println("After call to asyncFetchImage") 
    } 
} 

Bây giờ, phần thú vị. Đây là chuỗi sự kiện:

Tôi nhấn nút loadImage. Phương thức IBAction chạy.

Nó được tham chiếu đến trình quản lý tải xuống không đồng bộ singleton.

Nó hiển thị một thông báo, sau đó gọi đếnAsyncManager.asyncFetchImage. Phương thức AsyncManager.asyncFetchImage hiển thị một thông báo trên mục nhập, xếp hàng một cuộc gọi để tải hình ảnh 3 giây sau đó, hiển thị thông báo "rời" và trả về, trước khi hình ảnh được tải. Không có gì để trả lại, vì mã tải hình ảnh vẫn chưa chạy.

Phương thức loadImage của trình điều khiển xem hiển thị thông báo "Sau khi gọi đến asyncFetchImage" và trả về.

Một vài giây sau, mã bên trong asyncFetchImage thực sự chạy. Nó hiển thị một tin nhắn, tải hình ảnh, sau đó gọi trình xử lý hoàn thành.

Dưới đây là tập hợp các thông điệp bạn nhận được trở lại khi bạn chạy đoạn code trên:

about to call asyncFetchImage 
Entering asyncFetchImage(imageName:completion:) 
Leaving asyncFetchImage(imageName:completion:) 
After call to asyncFetchImage 
Loading image in background 
About to call completion handler 
Beginning completion block 
In completion block, status = image loaded 

Lưu ý rằng các dòng cuối cùng của LoadImage IBAction:

println("After call to asyncFetchImage") 

hiển thị một tin nhắn trước khi thông điệp về việc tải một hình ảnh được hiển thị. Cuộc gọi mã đến asyncFetchImage sẽ trả về ngay lập tức, trước khi thực hiện bất kỳ công việc nào. Mã sau khi cuộc gọi đến asyncFetchImage chạy tiếp theo, nhưng hình ảnh vẫn chưa được tải. Không có cách nào để trả lại kết quả tại thời điểm này, vì tải hình ảnh chưa bắt đầu.

+0

xin lỗi, hãy kiểm tra mã được cập nhật. Tôi đã bỏ lỡ một dòng. –

+0

Bạn vẫn không hiểu cách khối hoàn thành hoạt động. –

+0

rất có thể, tôi mới lập trình xin lỗi. –

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