Lately, I’ve been working on a fun side project involving the MailCore2 library. This tool allows you to work with emails protocols, such as IMAP and SMTP in my case. Mailcore2 is a cross platform library written in C++ with native bindings for the iOS, Android, Windows and Linux platforms. It’s super easy to use (and works with Carthage!) but as it’s often the case with 3rd party libraries: interfacing with ReactiveSwift is not pretty.

/// Fetch a message from the INBOX folder by its unique id func fetchMessage ( with uid : UInt32 ) -> SignalProducer < Item , TimelineError > { return SignalProducer { sink , disposable in let operation = session . fetchMessageByUIDOperation ( withFolder : "INBOX" , uid : uid ) operation ? . start { error , messageContent in // handle errors, decode message... } disposable . add { operation ? . cancel () } } }

When ReactiveCocoa 3 was released, the API exposed a rac_dataWithRequest extension on NSURLSession to perform a HTTP request the “reactive” way: you would rely on a SignalProducer instead of the “normal” approach using a completion block.

let URLRequest = NSURLRequest ( ... ) let producer = NSURLSession . sharedSession () . rac_dataWithRequest ( URLRequest ) producer . startWithNext { data , URLResponse in /// Handle error, decode data... }

This project is using the latest version of ReactiveSwift that comes with a much more clever way of “Reactifying” your code: ReactiveExtensionsProvider. If you look at the code, conforming to this protocol adds a reactive parameter on your object. Thanks to protocol extensions, this parameter returns your object wrapped in a Reactive struct you can add methods to. In our case, we want the code that fetches a message to be made more reactive.

extension MCOIMAPFetchContentOperation : ReactiveExtensionsProvider {} public enum MailCoreError : Error { case internalError ( Error ) case unknownError } extension Reactive where Base : MCOIMAPFetchContentOperation { func content () -> SignalProducer < MCOMessageParser , MailCoreError > { return SignalProducer { [ base = self . base ] sink , disposable in disposable += { base . cancel () } base . start { error , data in if let error = error { sink . send ( error : . internalError ( error )) } else if let data = data { sink . send ( value : MCOMessageParser ( data : data )) sink . sendCompleted () } else { sink . send ( error : . unknownError ) } } } } } func fetchMessage ( with uid : UInt32 ) -> SignalProducer < Message , MailCoreError > { let operation = session . fetchMessageByUIDOperation ( withFolder : "INBOX" , uid : uid ) return operation !. reactive . content () . map { /* map to Message */ } }

It’s not much more pretty but the code making this operation reactive is now isolated and easily testable. I, for one, am super happy with how the contributors have shapped ReactiveCocoa 5: it’s amazing to use.