1

I study code, and have Event object:

typealias AnyDict = [String: Any]

class Event {
  let repo: String
  let name: String
  let imageUrl: URL
  let action: String

  // MARK: - JSON -> Event
  init(dictionary: AnyDict) {
    guard let repoDict = dictionary["repo"] as? AnyDict,
      let actor = dictionary["actor"] as? AnyDict,
      let repoName = repoDict["name"] as? String,
      let actorName = actor["display_login"] as? String,
      let actorUrlString = actor["avatar_url"] as? String,
      let actorUrl  = URL(string: actorUrlString),
      let actionType = dictionary["type"] as? String
      else {
        fatalError()
    }

    repo = repoName
    name = actorName
    imageUrl = actorUrl
    action = actionType
  }

  // MARK: - Event -> JSON
  var dictionary: AnyDict {
    return [
      "repo" : ["name": repo],
      "actor": ["display_login": name, "avatar_url": imageUrl.absoluteString],
      "type" : action
    ]
  }
}

In my viewController class i have code that load data from Api and fill output Events object models. Complete code look like that:

let response = Observable.from([repo])
        .map { urlString -> URL in
            return URL(string: "https://api.github.com/repos/\(urlString)/events")!
    }
        .map { url -> URLRequest in
            return URLRequest(url: url)
    }
        .flatMap { request -> Observable<(HTTPURLResponse, Data)> in
            return URLSession.shared.rx.response(request: request)
    }
    .shareReplay(1)

    response
        .filter { response, _ in
            return 200..<300 ~= response.statusCode
    }
        .map { _, data -> [[String: Any]] in
            guard let jsonObject = try? JSONSerialization.jsonObject(with: data,
                                                                     options: []),
                let result = jsonObject as? [[String: Any]] else {
                    return [] }
            return result
    }
        .filter { objects in
            return objects.count > 0
    }
        .map { objects in
            return objects.map(Event.init)
    }
        .subscribe(onNext: { [weak self] newEvents in
            self?.processEvents(newEvents)
        })
        .disposed(by: bag)

My question is - i don't understand meaning of :

.map { objects in
            return objects.map(Event.init)

I realize that somehow that piece of code give us Event objects from [String: Any] object.

But i dont understand objects.map(Event.init). For me, in map we should perform actions with corresponding type, something like { Event.init(with: $0) } or something like that. What is meaning of objects.map(Event.init)? And how does it work?

Evgeniy Kleban
  • 6,794
  • 13
  • 54
  • 107

1 Answers1

3

map(Event.init) and map({Event.init(with: $0)}) are equivalent.

Think of it this way, map requires a closure that takes something of type T and return something of type U. {Event.init(with: $0)} is such a closure (takes an argument $0, creates a new Event and returns it), so you can pass it in.

But don't forget that methods and initialisers are also a type of closure. The initializer of Event, which takes one argument and returns an Event is compatible with what the map method needs! So instead of passing a closure using the {} syntax, you can just say "use the initializer of Event!" by doing: map(Event.init)

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • thank for detailed answer. In my case, init(dictionary: AnyDict) { will be called? – Evgeniy Kleban Nov 12 '17 at 13:38
  • kind of confusing, is that some kind of swift closure syntax sugar or something? For me it would be better to write map({Event.init(with: $0)}). Init with no parameters is kind of odd :) – Evgeniy Kleban Nov 12 '17 at 13:46
  • @EvgeniyKleban I don't believe it is syntactic sugar. It's just because of the fact that functions, methods and initialisers are treated as first class citizens and can be used as values of function types like `(AnyDict) -> Event`. If you don't like it this way, write it however you like. – Sweeper Nov 12 '17 at 13:48