Skip to content

πŸ•° A simple Future type in Swift

License

Notifications You must be signed in to change notification settings

tjek/swift-future

Folders and files

NameName
Last commit message
Last commit date
Jan 11, 2021
Oct 21, 2019
Jan 11, 2021
Oct 26, 2021
Sep 8, 2022
Mar 27, 2019
May 2, 2019
Mar 29, 2019
Jan 11, 2021
Jan 11, 2021
Sep 8, 2022
Sep 8, 2022

Repository files navigation

πŸ•° Future

Swift 5 Cocoapods License

A Future just represents some 'work', that may take some time (or not).

The power of Futures is that they can be chained togther, producing a single Future object that contains all the work of all the component Futures.

Furthermore, the work of this Future isnt done until you actually run the future.

Here is an example of the kinds of complex logic possible with Futures:

struct User: Codable {
    var id: String
    var name: String
}

struct Food: Codable {
    var type: String
    var tastiness: Int
}
    
// Make a future that loads a user value from the file "User.json"
let loadFileUser: FutureResult<User> = Bundle.main
    .loadData(forResource: "User.json")
    .flatMapResult(User.decodeJSON(from:))

// Make a future that loads food value from the json string
let loadStringFood: FutureResult<Food> = Future<String>
    .init(value: #"{ "type": "curry", "tastiness": 1000 }"#)
    .map({ $0.data(using: .utf8)! })
    .flatMap(Food.decodeFutureJSON(from:))

// Make a future that loads another user value from a network request
let loadNetworkUser: FutureResult<User> = URLSession.shared
    .dataTaskFutureResult(with: URLRequest(url: URL(string: "https://foo.bar")!))
    .mapResult({ $0.data })
    .flatMapResult(User.decodeFutureJSON(from:))
    
// zip the 3 futures together and, if all successful, convert the response into a string.
let combinedFuture = zipResult3With(
    loadStringFood,
    loadFileUser,
    loadNetworkUser
) { (food: $0, user: $1, networkUser: $2) }
    .mapResult({
        "\($0.user.name) likes \($0.food.type) x\($0.food.tastiness)... networkUser: '\($0.networkUser.name)'"
    })
    
// once it is finally run, print the result
combinedFuture.run { result in
    print(result)
} 

Future areas to improve:

  • FutureOptional - add tests and functionality similar to Future<Result<_,_>>
  • Cancellable - Somehow allow Futures to provide cancellable tokens.
  • More utility extensions
    • UIImageView().setImage(Future<UIImage?>)
    • CLGeocoder().geocode(...) -> FutureResult<[CLPlacemark]>
    • Maybe CLLocationManager... how to handle delegates? Future's arent the right thing for streams of events, I think. But sometimes we need 1-hit delegate calls.