:  ~ 2 min read

Optionals, flatMap and you

Say we have a UILabel where we want to display a birthdate with a full format, and an API from where we get a String? with iso8601 format. One of the ways to do this would be:

let dateFromAPI: String?

// [...]

let dateFormatter = DateFormatter.shared // 1
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"

if let dateString = dateFromAPI, // 2
   let date = dateFormatter.date(from: dateString) { // 3
   dateFormatter.dateFormat = nil
   dateFormatter.dateStyle = .full

   dateLabel.text = dateFormatter.string(from: date) // 4
}

DateFormatters are expensive to create, so we either create it here once, or use a shared one (1), we then check to see if we have a date from our API (2), then check if we can transform it to a date (3), then finally we can assign it to our dateLabel.text (4).

What about flatMap?

let dateFromAPI: String?

// [...]

let dateFormatter = DateFormatter.shared

dateLabel.text = dateFromAPI
   .flatMap { // 1
      dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"

      return dateFormatter.date(from: $0) // 2
   }
   .flatMap { // 3
      dateFormatter.dateFormat = nil
      dateFormatter.dateStyle = .full

      return dateFormatter.string(from: $0) // 4
   }

If dateFromAPI is not nil, the first flatMap closure will be called (1), where we transform the String to a Date (2), which if it’s not nil (3), the second flatMap closure is called, where we transform the date intro a String (4), which will be assigned to dateLabel.text.

I’m a bit torn on which one is more readable, but other in other scenarios, using the latter might be preferable.