0

I'm slowly coming to terms with closures. This is taken from the following post:

https://medium.com/@stasost/ios-three-ways-to-pass-data-from-model-to-controller-b47cc72a4336

I understand the function definition requestData is taking a closure which is called with completion(data):

    class DataModel {
       func requestData(completion: ((data: String) -> Void)) {
          // the data was received and parsed to String
          let data = "Data from wherever"
          completion(data)
       }

}


class ViewController: UIViewController {
   private let dataModel = DataModel()
   override func viewDidLoad() {
      super.viewDidLoad()
      dataModel.requestData { [weak self] (data: String) in
            self?.useData(data: data)
      }
   }
   private func useData(data: String) {
       print(data)
   } 
}

While I understand requestData is being called in viewDidLoad below and that (data:String) is being passed into requestData I don't quite get what is being done when completion(data) is being called.

Is completion(data) executing the code that is happening after the keyword "in"?

{ [weak self] (data: String) in
            self?.useData(data: data)
      }

And I had a question about the order in which things are happening. Is it:

a) let data = "Data from wherever"
b) completion(data)
c) self?.useData(data: data)

In the current app I'm working on when the user starts the app I make an api call to load data. But i'm still a tiny bit unsure about how to tell the ViewController that the data has finished loading.

Thanks.

Mike
  • 1,281
  • 3
  • 14
  • 41
  • naming a `String` object/parameter `data` it is very misleading – Leo Dabus Feb 17 '18 at 02:25
  • First you need to execute a asynchronous task otherwise your completion handler is pointless – Leo Dabus Feb 17 '18 at 02:32
  • When you call `completion(data)` that triggers the completion block to execute and pass the `data` into that block so you can handle it. You will most likely need to have several closures to pass the data from the final function back to the top where you need to access it. You can check out [This Project I did](https://github.com/JZDesign/OnTheMap/blob/master/OnTheMap/Client.swift) The function I call to start is doAllTasks() and that steps into several other functions and when it finally gets to the last completion I can hand all of that step by step up the chain back to the beginning. – Jake Feb 17 '18 at 06:03
  • Possible duplicate of [Swift closures \[weak self\] and async tasks](https://stackoverflow.com/questions/30920576/swift-closures-weak-self-and-async-tasks) – Cristik Feb 17 '18 at 06:36

1 Answers1

2

You understand that a function can take, say, an Int as parameter?

func f(_ i:Int) { 
    // do something with i
}

Well, a function can also take a function as parameter:

func requestData(completion: ((data: String) -> Void)) {
    // do something with completion
}

In that declaration, completion is a function — a function that takes one parameter, called data.

What can you do when you receive a function as a parameter? One obvious thing to do with it would be to call it:

func requestData(completion: ((data: String) -> Void)) {
   completion(data: "well howdy there")
}

It remains only to talk about the syntax of passing the desired function to requestData as its completion parameter. Here is one way:

func output(data: String) {
    print(data)
}
requestData(completion:output)

Here's a nicer way, one that avoids giving the passed function a name:

requestData(completion:{
    data in
    print(data)
})

Finally, since completion is the only parameter, we are allowed to use "trailing closure" syntax — we delete the completion: label and the parentheses of the call:

requestData {
    data in
    print(data)
}
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • It might help you to read the part of my book that discusses this topic, i.e. passing a function into a function whose job is to call it: http://www.apeth.com/swiftBook/ch02.html#_function_as_value – matt Feb 17 '18 at 02:52
  • 1
    "trailing closure" syntax it is not restrict to single parameter – Leo Dabus Feb 17 '18 at 03:05
  • @LeoDabus All very simplified and curtailed for pedagogical purposes; for the full and correct details the OP can see the link I gave him. – matt Feb 17 '18 at 03:58
  • @matt. that's great. – Mike Feb 18 '18 at 05:00