异步闭包如何在Swift中工作

时间:2016-11-27 08:37:40

标签: objective-c swift closures

我在我的swift项目中使用了在objective-c中编写的基于nsurlssesion的包装器class。 Everthing正在发挥作用,除非我无法解决关闭如何在swift中工作。

在我的swift viewcontroller中:

 DownloadManager().downloadFile(forURL: url, progressBlock: { (progress) -> () in
            print("current progress is \(progress)")
        }, completionBlock: { (completion) in
            print("is completed : \(completion)")
        }, enableBackgroundMode: false)

在我的Downloadmanager类(基于objc)中,无论何时调用nsurlssession委托,都会发生这种情况:

 dispatch_async(dispatch_get_main_queue(), ^(void) {
            if(download.progressBlock){
                download.progressBlock(progress); //exception when progressblock is nil
            }
        });

下载对象有一个名为progressBlock的块类型属性:

typedef void(^TWRDownloadProgressBlock)(CGFloat progress);

输出:

current progress is 0.0908259372799894
current progress is 0.272477811839968
current progress is 0.363303749119957
current progress is 0.454129686399947
current progress is 0.544955623679936
current progress is 0.635781560959925
current progress is 0.726607498239915
current progress is 0.817433435519904
current progress is 1.0

代码流程:

  1. NSURlsession称之为委托方法。
  2. DowloadManager更新下载对象的进度变量。
  3. 在我的viewcontroller中,我可以在闭包内看到progress变量的更新值。
  4. 问题: 第3点是如何发生的?

    这是关闭在swift中表现的标准方式吗?具体来说,我想知道每次Dowload对象更改时是否自动调用闭包?

1 个答案:

答案 0 :(得分:1)

根据The Swift Guide

  

闭包是自包含的功能块,可以在代码中传递和使用。 Swift中的闭包类似于C和Objective-C中的块以及其他编程语言中的lambdas。

     

闭包可以从定义它们的上下文中捕获和存储对任何常量和变量的引用。

在这种情况下,闭包在视图控制器中定义,然后传递 周围和后来打电话。

流程如下:

  1. 创建TWRDownloadManager()的新实例并调用其downloadFile方法。
  2. 在此调用中,传递progressBlock: ((CGFloat) -> Swift.Void)闭包(它将CGFloat作为参数并且不返回任何内容)。
  3. 在这一行中,这个块被分配给TWRDownloadObject()。progressBlock
  4. 接下来,NSURLSession Delegate方法调用download.progressBlock(progress),它只是从#2调用闭包并将CGFloat值作为参数传递。
  5. 这是一个快速的游乐场示例:

    import Foundation
    import PlaygroundSupport
    import TWRDownloadManager
    
    PlaygroundPage.current.needsIndefiniteExecution = true
    
    let downloadManager = TWRDownloadManager()
    let url = "http://download.thinkbroadband.com/200MB.zip"
    
    let progressClosure: (CGFloat) -> () = { (progress) in
    
        print("current progress is \(progress)")
    
    }
    
    let completionClosure: (Bool) -> () = { (completion) in
    
        print("is completed : \(completion)")
    
    }
    
    downloadManager.downloadFile(
        forURL: url,
        progressBlock: progressClosure,
        completionBlock: completionClosure,
        enableBackgroundMode: false
    )