-2

I'm working a tutorial from https://www.raywenderlich.com/921-cocoa-bindings-on-macos. I'm wondering what the .enumerated() and .map() functions are operating on in this section:

@IBAction func searchClicked(_ sender: Any) {

  guard let resultsNumber = Int(numberResultsComboBox.stringValue)
    else {
      return
  }
  iTunesRequestManager.getSearchResults(searchTextField.stringValue, results: resultsNumber, langString: "en_us") { (results, error) in
    let itunesResults = results.map {
      return Result(dictionary: $0)
    }

      .enumerated()
      .map({ (index, element) -> Result in
        element.rank = index + 1
        return element
      })

    DispatchQueue.main.async {
      self.searchResultsController.content = itunesResults
      print(self.searchResultsController.content!)
    }
  }

}

I can usually figure out most things eventually in Swift but I'm stumped here and the explanatory text isn't clear to me either. I hope someone can help me understand this part of the tutorial. Thanks!

JamesH
  • 67
  • 6
  • 1
    Have you looked up the API documentations for enumerator aor map? – Alexander Dec 26 '19 at 23:11
  • Yes I have, but in the documentation examples shown, what is being operated on is defined clearly (for me) such as: for (n, c) in "Swift".enumerated() { print("\(n): '\(c)'") and: let cast = ["Vivien", "Marlon", "Kim", "Karl"] let lowercaseNames = cast.map { $0.lowercased() } } – JamesH Dec 27 '19 at 00:11
  • 1
    `cast` is just an `Array` (a.k.a. `[String]`). But so is `lowercaseNames` (the result of a call to `map`. There's no difference between values made via literals (e.g. `cast`), and those made via calls to functions (e.g. `lowercaseNames`) – Alexander Dec 27 '19 at 18:36

1 Answers1

1
  1. Map is used for modifications. At this point you are basically initialising an object of Result by giving results array as a param to it:
results.map {
   return Result(dictionary: $0)
}

$0 means the first input. In a following case, $0 is equal to param(we just gave it a name):

results.map { param in
   return Result(dictionary: param)
}
  1. .enumerated() returns each element of an array with its index number. Without it you would have only the element like this:
 .map({ (element) -> Result in
        // you don't have `index` value inside the closure anymore
        // element.rank = index + 1
        return element
 })

Note that the element in the closure above is the same Result(dictionary: $0) object that you created in a previous map function.

  1. At the end, you are making and modification by assigning elements index number increased by 1 to the element's rank property, and returning it:
 .map({ (index, element) -> Result in
        // element.rank = index + 1
        return element
 })

Note that the value we get after the 3rd step, including all modification is assigned to let itunesResults.

Lew Winczynski
  • 1,190
  • 1
  • 11
  • 20
  • Thank you. This is complex but you've helped me understand it better. – JamesH Dec 27 '19 at 00:35
  • Great to hear that! Please, mark it as answer if it helped you :) @JamesH – Lew Winczynski Dec 27 '19 at 00:40
  • I did. I'm somewhat of a newbie here so I appreciate your thoughtful answer. Don't understand the downvotes for my question though without some clue as to what I could have done differently. I did quite a bit of research before coming here – JamesH Dec 27 '19 at 01:09
  • Also I just tried a similar sequence of calls in a playground on two arrays of strings. Apparently .enumerated() and .map() work on the last declared array, so in the tutorial the array (dictionary) they operated on was itunesResults. A lot of Swift's behavior is implied from context so I'll have to work through that. Thanks again, everything is so much clearer now. – JamesH Dec 27 '19 at 13:12