Slide 1

Slide 1 text

Building Fabric.app with Reac5veCocoa "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 1

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

"Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 8

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

Fabric App Architecture "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 12

Slide 13

Slide 13 text

Fabric App Architecture • FabricAPI.framework: • Networking • Models • Fabric App: • View Controllers • View Models "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 13

Slide 14

Slide 14 text

Examples of Usage of Reac0veCocoa in the Fabric App "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 14

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

DataLoadState final class MyViewModel { var data: MyEntity? } "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 16

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

extension SignalProducerType where Value: DataLoadState { func ignoreLoadingAndErrorsAfterSuccess() -> SignalProducer, 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

Slide 20

Slide 20 text

Examples - View Models typealias ApplicationLoadState = DataLoadState<[Application]> final class ApplicationListViewModel { let applications: AnyProperty 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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

Reac%veCocoa Extensions "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 22

Slide 23

Slide 23 text

extension SignalProducerType { func startWithValue(value: Value) -> SignalProducer { return SignalProducer(value: value).concat(self.producer) } } "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 23

Slide 24

Slide 24 text

Reac%veCocoa Extensions extension SignalProducerType { func startWithNil() -> SignalProducer { return self .map(Optional.init) .startWithValue(nil) } "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 24

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

Reac%veCocoa Extensions extension SignalProducerType { func failRandomly(withError error: Self.Error) -> SignalProducer { 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

Slide 27

Slide 27 text

Reac%veCocoa Extensions extension NSProcessInfo { var lowPowerModelEnabledProducer: SignalProducer { 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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

Reac%veCocoa Extensions extension SignalProducerType { func continueWhenApplicationIsBackgrounded( taskName taskName: String, timeoutError: Self.Error ) -> SignalProducer { } "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 29

Slide 30

Slide 30 text

Reac%veCocoa Extensions extension SignalProducerType { func repeatWith( producer: SignalProducer<(), NoError>, throttleWithInterval: NSTimeInterval, onScheduler scheduler: DateSchedulerType ) -> SignalProducer { 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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

Thank you! <3 ! See you next year! "Building Fabric.app with Reac6veCocoa" - Javier Soto. RACDC2016 - April 2016 34