2

I have been following a video tutorial, and have written the following code:

func downloadWeatherDetails(completed: ()->() ) {

    let currentWeatherURL = URL(string: CURRENT_WEATHER_URL)!

    Alamofire
        .request(currentWeatherURL)
        .responseJSON(completionHandler: { response in
        let result = response.result
        print(result)
    })
    completed()
}

So basically, my understanding is as follows. The .responseJSON handler lets you call code after the request has been fired. It allows you to specify a completionHandler, which in my case, is the closure:

{ response in
        let result = response.result
        print(result)
}

However, what I don't understand is what the "response" keyword actually signifies. I researched the usage of closures and saw that the syntax is:

{(param) -> returnType in { code here }

Thus, is the "response" keyword a parameter? If so, how is it being declared and where is the data coming from? How is the data passed into the "response" object? Also, why is only one parameter allowed? The code did not work if I made it as follows, for example:

{ (response, test) in
        let result = response.result
        print(result)
}

I would really appreciate a thorough explanation on this as I've found no help elsewhere online. I've gone through Apple's "The Swift Programming Language", a multitude of different explanations, and similar questions, but still do not understand completely.

Just to clarify, I do not believe my question is a duplicate since my question revolves primarily on the captured value stored in response rather than the syntax of closures as a whole. I went through the linked question while trying to figure out my own problem, but it did not help me sufficiently.

Minor clarification needed:

Is it always the case that when a method takes a closure as one of its parameters, for example, .testMethod(testParam: (String) -> ()) and would thus in practice be used: .testMethod(testParam: { (capturedVar) in statements} (correct me if im wrong), is it always the case that the parameter of the closure ((String) in this case) will be captured and stored in capturedVar? Will there always be data passed into the variable you define? Or is this cycle specific to alamofire?

mlz7
  • 2,067
  • 3
  • 27
  • 51
  • Possible duplicate of [Completion handlers in Swift 3.0](https://stackoverflow.com/questions/41745328/completion-handlers-in-swift-3-0) – Jaydeep Vora Aug 19 '17 at 03:55

1 Answers1

1

Swift closures are defined as:

{ (parameters) -> return_type in
    statements
}

That is, the names in parenthesis are the variables the closure has captured, and the -> type is the optional return type (optional because the compiler can usually infer it). Alamofire's responseJSON method captures a DataResponse<Any> parameter, which you can name whatever you want, but which is usually just named response. You can then access it inside that closure.

Also, your completed() call should be inside the responseJSON call, not outside, otherwise it just gets called immediately.

mlz7
  • 2,067
  • 3
  • 27
  • 51
Jon Shier
  • 12,200
  • 3
  • 35
  • 37
  • Is there any way to view the captured parameter(s) type for a closure within xcode? – mlz7 Aug 19 '17 at 03:53
  • 1
    A breakpoint inside the closure will show the capture variables, but only if you've named them (i.e. didn't use `_` or capture them as a single tuple). You can also view the inline documentation for any method, which should include the signatures of any closure parameters, by option clicking them in Xcode. – Jon Shier Aug 19 '17 at 03:56
  • So holding option, it shows: `completionHandler: @escaping (DataResponse) -> Void) -> Self` Based on your explanation, the DataResponse is the captured variable which is being stored in `response` (please tell me if im wrong), however, what does the `-> Self` part mean? – mlz7 Aug 19 '17 at 04:17
  • Also, I'm assuming that the reason for not doing `{ response -> return_type in statements` is because the `completionHandler` param returns `void` so the `return_type` is not needed? – mlz7 Aug 19 '17 at 04:32
  • Like I said, the return type can be inferred, which is easy in the case of `Void` but can work in many other cases as well. As for the handler signature, your understanding is correct. The `Self` return value is actually part of the overall `responseJSON` method, not the closure. It's used to mean that the method return a value of the type of class it's called on. So if you made a subclass of `DataRequest` it would return that type instead of just `DataRequest`. – Jon Shier Aug 19 '17 at 04:34
  • Is it always the case that when a method takes a closure as one of its parameters, for example, `.testMethod(testParam: (String) -> ())` and would thus in practice be used: `.testMethod(testParam: { (capturedVar) in statements}` (correct me if im wrong), is it always the case that the parameter of the closure (`(String)` in this case) will be captured and stored in `capturedVar`? Will there always be data passed into the variable you define? Or is this cycle specific to alamofire? – mlz7 Aug 19 '17 at 20:13