Reputation: 3357
I am using a nsurlssesion based wrapper class written in objective-c in my swift project. Everthing is working except I am not able to undertand how the closure works in swift.
In my swift viewcontroller:
DownloadManager().downloadFile(forURL: url, progressBlock: { (progress) -> () in
print("current progress is \(progress)")
}, completionBlock: { (completion) in
print("is completed : \(completion)")
}, enableBackgroundMode: false)
In my Downloadmanager class (which is objc based) whenever nsurlssession delegate is called this happens:
dispatch_async(dispatch_get_main_queue(), ^(void) {
if(download.progressBlock){
download.progressBlock(progress); //exception when progressblock is nil
}
});
Download object have a block type property called progressBlock :
typedef void(^TWRDownloadProgressBlock)(CGFloat progress);
Output:
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
Flow of the code:
Question: How is point-3 happening?
Is this the standard way closure behaves in swift? Specifically, I would like to know if the closure is automatically called everytime Dowload object changes?
Upvotes: 1
Views: 578
Reputation: 323
According to The Swift Guide:
Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages.
Closures can capture and store references to any constants and variables from the context in which they are defined.
In this case, a closure is defined within the view controller, then passed around and called later.
The flow would be as follows:
downloadFile
method.progressBlock: ((CGFloat) -> Swift.Void)
closure (it takes CGFloat as a parameter and returns nothing).download.progressBlock(progress)
, which simply calls the closure from #2 and passes the CGFloat value as its parameter.Here is quick Playground example:
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
)
Upvotes: 1