/RxParseCallback

Syntactic sugar to convert block based callbacks into RxSwift Observables

Primary LanguageSwiftMIT LicenseMIT

RxParseCallback

Swift Carthage compatible Swift Package Manager compatible

Syntactic sugar to convert block based callbacks into RxSwift Observables

Usage

Are you tied down to a callback based API, wishfully looking on at RxSwift? RxParseCallback makes adopting RxSwift in your project way easier!

It let's you turn

API.doTheThing { [weak self] thing in
  guard strongSelf = self else { return }
  
  strongSelf.thing.value = thing
}

into

API.rx.doTheThing.bindTo(self.thing)

✨ Isn't that beautiful?

Here's a real life example, that wraps the Facebook iOS SDK's login function

func login(withReadPermissions permissions: [String] = ["email", "public_profile", "user_friends"]) -> Observable<FBSDKLoginManagerLoginResult> {

  return ParseRxCallbacks.createWithCallback({ observer -> Void in ⬅️ is interesting
    FBSDKLoginManager().logIn(withReadPermissions: permissions, 
                              from: nil,
                              // so is ⬇️
                              handler: ParseRxCallbacks.parseUnwrappedOptionalCallback(observer))
  })

}

The handler param is of type (FBSDKLoginManagerLoginResult?, Error?) -> Void, and calling ParseRxCallbacks.parseUnwrappedOptionalCallback(observer) returns (T?, Error?) -> Void. Which conforms to the handler's (FBSDKLoginManagerLoginResult?, Error?) -> Void (the compiler infers T to be FBSDKLoginManagerLoginResult) #connectingmagic

Installation

RxParseCallback is tiny — it's just one file — 55 lines

These are the currently supported methods of installation

Create a Package.swift file.

import PackageDescription

let package = Package(
    name: "MyProjectThat<3sRx",
    targets: [],
    dependencies: [
        .Package(url: "https://github.com/AndrewSB/RxParseCallback.git", majorVersion: 1)
    ]
)
$ swift build

Add this to Cartfile

github "AndrewSB/RxParseCallback" ~> 1.0
$ carthage update

Manual

First make sure you have access to RxSwift in your project. Then you can grab the Source/RxParseCallback.swift file, and drag it into your project.

API

Creating an Observable

func createWithCallback(_ callback: @escaping ((AnyObserver<T>) -> Void)) -> Observable<T>

Allows you to create an observable from a block. This is the meat of this µ Library. Inside the callback, you get a AnyObserver<T>, to which you can send any events you want propogated through the returned Observable<T>

Convinience functions for parsing conventional callback based APIs

Most APIs have callbacks that look something like (T?, Error?). So there are three functions that help parsing data out of that common pattern.

Callbacks that return (T, Error?)
func parseCallback<T>(_ observer: AnyObserver<T>) -> (T, Error?)

This works for callbacks that have callbacks that return (T, Error?). So you pass in the AnyObserver<T> given to you from the createWithCallback, and it satisfies the type requirment of (T, Error?)

Callbacks that return (T?, Error?)
func parseOptionalCallback<T>(_ observer: AnyObserver<T?>) -> (T?, Error?)

Same as above, but it accepts callbacks that pass in (T?, Error?) instead.

Callbacks that return (T?, Error?)
func parseUnwrappedOptionalCallback<T>(_ observer: AnyObserver<T>) -> (T?, Error?)

Same as above, but it also goes ahead and (safely) unwraps the T? into a T if the error was nil. If both the error and T are nil, it sends an error through on the Observable, called noObjectNorErrorIncluded

License

RxParseCallback is under the MIT license. See the LICENSE file for more info.