1

Teaching myself Swift, and looking at this answer here.

The part that's confusing me the most is this bit:

let task = URLSession.shared.dataTask(with: request) { data, 
response, error in
    guard let data = data, error == nil else {
        print(error?.localizedDescription ?? "No data")
        return
    }
    let responseJSON = try? JSONSerialization.jsonObject(with: data, 
    options: [])
    if let responseJSON = responseJSON as? [String: Any] {
        print(responseJSON)
    }
}

I'll walk through the parts I do understand, and I'm hoping someone can help me fill in the gaps.

  1. The let task = ... part is assigning a new URLSessionDataTask object to the variable task with the passed in request data. I get that.
  2. data, response, and error (followed by in) seem to be placeholder parameters. Is this correct? And does the in keyword signify that these are input parameters? I read on Apple's documentation that they can be in-out parameters, so I'm thinking that's what this means. This mini-function of sorts accepts, rather than returns, something.
  3. guard let data = ... this is a weird concept coming from other languages. From what I understand, the guard statement defines a set of Bool/boolean expressions, all of which have to be true, else the code inside the block is executed. So basically, if data cannot receive anything, and if error is nil/null, print an error message and return.
  4. If all else is successful, print the JSON response and finish.

I guess the most foreign concept to me is the let ... _, _, _ in statement, since the syntax just looks really weird (placeholder parameters come after the opening {?)

I tried searching for documentation on this type of statement, and Apple compared it to a lambda expression in other languages. I can sort of see that with the data, response, error part.

So, if anyone can help clear a couple things up about this, it'd be much appreciated. Thanks!

rmaddy
  • 314,917
  • 42
  • 532
  • 579
David Mordigal
  • 813
  • 2
  • 9
  • 22
  • Your second question! “`in` keyword indicates that the definition of the closure’s parameters and return type has finished, and the body of the closure is about to begin.” From Apple's documentation – Mannopson Nov 26 '17 at 06:51
  • Look at the documentation for the `URLSession dataTask(with:completionHandler:)` method. – rmaddy Nov 26 '17 at 06:52
  • Then review the [Closures](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html#//apple_ref/doc/uid/TP40014097-CH11-ID94) chapter (with a focus on the [Trailing Closures](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html#//apple_ref/doc/uid/TP40014097-CH11-ID94) section) of the Swift book. – rmaddy Nov 26 '17 at 06:54
  • Here's another blog (Swift 3 but I believe no changes for Swift 4) about completion handlers that may be more relevant to the specifics in your question: https://grokswift.com/completion-handlers-in-swift/ –  Nov 26 '17 at 07:13
  • Thanks all for your information. @dfd, this looks like a great blog, thanks much for sharing it. – David Mordigal Nov 26 '17 at 07:57

1 Answers1

2

The let ... _, _, _ in thing can't really be discussed in this form, since it is not a single syntax (like an if statement or while loop), but a bunch of different things put together.

  • let task declares a constant, whose type is inferred.
  • URLSession.shared.dataTask(... calls a method in the URLSession class called dataTask. Its parameters are:
    • a request, which you have passed using a variable called request.
    • a closure, taking 3 parameters and returning nothing.
  • Since the closure is the last parameter, the trailing closure syntax can be used here. This means that the closure can be written outside of the parentheses that are supposed to contain all the parameters. This is the closure that you passed in:

    { data, response, error in
        guard let data = data, error == nil else {
            print(error?.localizedDescription ?? "No data")
            return
        }
        let responseJSON = try? JSONSerialization.jsonObject(with: data, 
        options: [])
        if let responseJSON = responseJSON as? [String: Any] {
            print(responseJSON)
    }
    
  • data, response, error are the closure's parameters. Again, their types are inferred.

  • the word in is just part of the how-you-write-a-closure syntax. Think of it as saying "right, I'm now done with writing the parameters and capture list, moving on to what this closure's gonna do!"
Sweeper
  • 213,210
  • 22
  • 193
  • 313