Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Building Fabric.app with ReactiveCocoa

Building Fabric.app with ReactiveCocoa

Overview of how the Fabric App was built by taking advantage of some of ReactiveCocoa's features.

C0eafab7106ab63b8db4025e57c1a8d2?s=128

Javier Soto

June 15, 2016
Tweet

More Decks by Javier Soto

Other Decks in Programming

Transcript

  1. Building Fabric.app with Reac5veCocoa "Building Fabric.app with Reac6veCocoa" - Javier

    Soto. RACDC2016 - April 2016 1
  2. Intro @Javi "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016

    - April 2016 2
  3. Outline • Intro • History • Contribu.ng to Reac.veCocoa •

    Fabric App Architecture • RAC examples from Fabric App "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 3
  4. Intro: What is Fabric.app? "Building Fabric.app with Reac6veCocoa" - Javier

    Soto. RACDC2016 - April 2016 4
  5. What is Fabric.app? "Building Fabric.app with Reac6veCocoa" - Javier Soto.

    RACDC2016 - April 2016 5
  6. History h"ps:/ /github.com/blog/1107-reac8vecocoa-for-a-be"er-world "Building Fabric.app with Reac6veCocoa" - Javier Soto.

    RACDC2016 - April 2016 6
  7. History • Reac&veCocoa 1: May 2012 (Objec&ve-C) • Reac&veCocoa 2:

    September 2013 (Objec&ve-C) • Reac&veCocoa 3: September 2015 (Swi@ 1) • Reac&veCocoa 4: January 2016 (Swi@ 2) "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 7
  8. "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April

    2016 8
  9. Contribu)ng to Reac)veCocoa "Building Fabric.app with Reac6veCocoa" - Javier Soto.

    RACDC2016 - April 2016 9
  10. Contribu)ng to Reac)veCocoa: Coding • Refactoring • New tests •

    Proposing new operators • Compa5bility with new Swi; versions "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 10
  11. Contribu)ng to Reac)veCocoa: Other ways! • Replying to issues •

    Wri1ng / improving docs • Helping other users • Evangelizing "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 11
  12. Fabric App Architecture "Building Fabric.app with Reac6veCocoa" - Javier Soto.

    RACDC2016 - April 2016 12
  13. Fabric App Architecture • FabricAPI.framework: • Networking • Models •

    Fabric App: • View Controllers • View Models "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 13
  14. Examples of Usage of Reac0veCocoa in the Fabric App "Building

    Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 14
  15. Examples - Networking final class AuthenticatedFabricAPI { func applications() ->

    SignalProducer<[Application], FabricAPIError> { return apiNetworking.requestJSONProducer( URL: APIURL(path: "api/v3/projects"), method: .GET ) .attemptMap(Application.decodeObjectsInJSON) .observeOn(UIScheduler()) } } "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 15
  16. DataLoadState final class MyViewModel { var data: MyEntity? } "Building

    Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 16
  17. DataLoadState enum DataLoadState<DataType> { case Loading case Failed case Loaded(DataType)

    } "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 17
  18. DataLoadState enum DataLoadState<DataType> { case Loading case Failed case Loaded(DataType)

    } extension SignalProducerType { func materializeToLoadState() -> SignalProducer<DataLoadState<Value>, NoError> { let producer = self .map(DataLoadState.Loaded) .startWithValue(DataLoadState.Loading) return producer.ignoreErrors(replacementValue: DataLoadState<Value>.Failed) } } "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 18
  19. extension SignalProducerType where Value: DataLoadState { func ignoreLoadingAndErrorsAfterSuccess() -> SignalProducer<DataLoadState<Value.DataType>,

    Error> { var hasSuccededOnce = false return self.filter { value in defer { if value.success { hasSuccededOnce = true } } return !hasSuccededOnce || value.success } } "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 19
  20. Examples - View Models typealias ApplicationLoadState = DataLoadState<[Application]> final class

    ApplicationListViewModel { let applications: AnyProperty<ApplicationLoadState> private let applicationsMutableProperty = MutableProperty(ApplicationLoadState.loading()) init(fabricAPI: AuthenticatedFabricAPI) { self.applications = AnyProperty(self.applicationsMutableProperty) self.applicationsMutableProperty <~ fabricAPI.applications().materializeToLoadState() } } "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 20
  21. Examples - Consuming Data From a View Model self.viewModel.applications.producer.startWithNext {

    applicationsLoadState in switch applicationsLoadState { case .Loading: label.text = "Loading..." case .Failed: label.text = "Error loading applications!" case .Loaded(let applications): reloadTableView(applications: applications) } } "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 21
  22. Reac%veCocoa Extensions "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016

    - April 2016 22
  23. extension SignalProducerType { func startWithValue(value: Value) -> SignalProducer<Value, Error> {

    return SignalProducer(value: value).concat(self.producer) } } "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 23
  24. Reac%veCocoa Extensions extension SignalProducerType { func startWithNil() -> SignalProducer<Value?, Error>

    { return self .map(Optional.init) .startWithValue(nil) } "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 24
  25. Reac%veCocoa Extensions extension SignalProducerType { func ignoreErrors( replacementValue replacementValue: Self.Value?

    = nil ) -> SignalProducer<Value, NoError> { return self.flatMapError { _ in return replacementValue.map(SignalProducer.init) ?? .empty } } "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 25
  26. Reac%veCocoa Extensions extension SignalProducerType { func failRandomly(withError error: Self.Error) ->

    SignalProducer<Value, Error> { return self.attemptMap { value in let shouldFail = arc4random() % 3 == 0 return shouldFail ? Result(error: error) : Result(value: value) } } "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 26
  27. Reac%veCocoa Extensions extension NSProcessInfo { var lowPowerModelEnabledProducer: SignalProducer<Bool, NoError> {

    return NSNotificationCenter.defaultCenter() .rac_notifications(NSProcessInfoPowerStateDidChangeNotification, object: nil) .map { _ in return () } .startWithValue(()) .map { [unowned self] _ in return self.lowPowerModeEnabled } .skipRepeats(==) } } "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 27
  28. Reac%veCocoa Extensions let shouldReload = combineLatest( viewIsOnScreen, NSProcessInfo.processInfo().lowPowerModelEnabledProducer.map { !$0

    } ).map { $0 && $1 } let reloadPeriodically = shouldReload .flatMap(.Latest) { [unowned self] shouldReload in return shouldReload ? timer(30, onScheduler: scheduler).map { _ in () } : .empty } let request = reloadPeriodically.flatMap(.Latest) { someAPIRequest } "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 28
  29. Reac%veCocoa Extensions extension SignalProducerType { func continueWhenApplicationIsBackgrounded( taskName taskName: String,

    timeoutError: Self.Error ) -> SignalProducer<Value, Error> { } "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 29
  30. Reac%veCocoa Extensions extension SignalProducerType { func repeatWith( producer: SignalProducer<(), NoError>,

    throttleWithInterval: NSTimeInterval, onScheduler scheduler: DateSchedulerType ) -> SignalProducer<Value, Error> { return SignalProducer(value: ()).concat(producer) .throttle(throttleWithInterval, onScheduler: scheduler) .promoteErrors(Error) .flatMap(.Concat) { _ in return self.producer } } } "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 30
  31. Reac%veCocoa Extensions self.api.request(parameterFoo: bar) .repeatWith( viewWillAppearProducer, throttleWithInterval: 60, onScheduler: QueueScheduler.mainQueueScheduler

    ) "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 31
  32. Conclusion "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 -

    April 2016 32
  33. Ques%ons? "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 -

    April 2016 33
  34. Thank you! <3 ! See you next year! "Building Fabric.app

    with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 34