ios reactive cocoa pipeline

Post on 14-Apr-2017

312 Views

Category:

Software

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Рак мозга или мозг рака

Раком можно все

1023

A for Architecture

•Application Layer

•Transport Layer

•Service Layer

•Model Layer

•ViewModel Layer

•View Layer

• Application Layer

•Transport Layer

•Service Layer

•Model Layer

•ViewModel Layer

•View Layer

Persistence Notifications Runtime

• Application Layer

•Transport Layer

•Service Layer

•Model Layer

•ViewModel Layer

•View Layer

NSNotification LocationUpdate

•Application Layer

• Transport Layer

•Service Layer

•Model Layer

•ViewModel Layer

•View Layer

Networking Networking policies

•Application Layer

• Transport Layer

•Service Layer

•Model Layer

•ViewModel Layer

•View Layer

HTTP.Request HTTP.Response HTTP.Error

•Application Layer

•Transport Layer

• Service Layer

•Model Layer

•ViewModel Layer

•View Layer

API Request Persistence Request Application Service wrapper

•Application Layer

•Transport Layer

• Service Layer

•Model Layer

•ViewModel Layer

•View Layer

Update request Value Object Service Object

•Application Layer

•Transport Layer

•Service Layer

• Model Layer

•ViewModel Layer

•View Layer

Business logic Logic state

•Application Layer

•Transport Layer

•Service Layer

• Model Layer

•ViewModel Layer

•View Layer

Model Object

•Application Layer

•Transport Layer

•Service Layer

•Model Layer

• ViewModel Layer

•View Layer

Application State Presentation Logic

•Application Layer

•Transport Layer

•Service Layer

•Model Layer

• ViewModel Layer

•View Layer

Bindings Presentables

•Application Layer

•Transport Layer

•Service Layer

•Model Layer

•ViewModel Layer

• View LayerPresentation UI State

•Application Layer

•Transport Layer

•Service Layer

•Model Layer

•ViewModel Layer

• View LayerPresenters UIObjects Foundation Types

Data Flow

1024

Data + Data Request Flow

Transport Layer

Transport Layer

Transport Layer + Errors

Transport Layer + Binding

And now?

RAC• Signal

• SignalProducer

• Action

• Property

• Result

RAC• Signal

• SignalProducer

• Action

• Property

• Result

• Pipeline

• Future Task

• Future Builder

• Reactive State

• Enum<Value | Error>

RAC• Signal

• SignalProducer

• Action

• Property

• Result

• NSNotificationCenter

• startWithCompletion:

• startWithInput:Completions

• value + KVO

• completions(result, error)

RAC + Transforms• Signal -> Signal - Operator

• Signal.map(transform)

• Signal.retry(3)

• Signal -> Signal -> Signal - pipeline

- retry(map(signal, transform), 3)

✓ signal.map(transform).retry(3)

RAC + (flat)map

Transport Layer + RAC

Transport Layer + RAC

let requestAction = Action<URLRequest, URLResponse, Error> { .../*future task*/ } let http = Action<Request, Response, Error> { request in return Result<Request, Error>(value: request) .flatMap(serialize) //Result<JSON, Error> .flatMap(requestBuilder(forConfiguration: configuration)) //Result<URLRequest, Error> .map(SignalProducer.init) //SignalProducer<URLRequest, Error> .flatMap(.Latest, transform: requestAction.apply) //SignalProducer<URLResponse, Error> .attemptMap(deserialize) //SignalProducer<Response Error }

Заметьте - эта штука вполне может быть общей вне зависимости от входных и выходных данных засчет generic

Build Your Own RAC

extension SignalType { /// Returns a signal that will yield an array of values when `self` completes. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func collect() -> Signal<[Value], Error> { return self .reduce(CollectState()) { $0.append($1) } .map { $0.values } } }

Transport Layer + RAC

let httpWithPolicy = Action<Request, Response, Error> { request in http.apply(request) .retry(3) .suspendOn(enterBackgroundSignal: background, enterForeground: foreground) }

Service Layer

Service Layer

Service Layer + RAC

let service = Action<Number, Image, Error> { number in let image = cacheService.inquire .apply(number) .concat { xkcdImageHTTP.apply(number) }

let description = xkcdDescriptionHTTP.apply(number)

return combineLatest(image, description).map { ImageWithDescription(image: $0, description: $1) } }

Model Layer

Model Layer

Model Layer + RAC

struct State { let number: Int let value: AnyProperty<ImageWithDescription?>

init(number: Int) { self.number = number self.value = AnyProperty(value: nil, producer: service.apply(number)) } }

let state = MutableProperty(State(number: 100)) let increment = { number.value = State(number: number.value.number + 1) }

let exposedState = AnyProperty(state)

View Model Layer

View Model Layer

VM Layer + RAC let image = model.exposedState .flatMap { $0.value.image } .map { $0 ?? imagePlaceholder }

let description = model.exposedState .flatMap { $0.value.description } .map { $0 ?? "Loading..." }

let rightButtonAction = model.increment

let present = { presenters in presenters.rightButtonAction <~ rightButtonAction presenters.description <~ description.producer presenters.image <~ description.image }

View Layer

View + RAC

class View { //{ self.imageView.image = $0 } let image: Presenter<UIImage> = self.imageView.imagePresenter //{ self.descriptionLabel.value = $0 } let description: Presenter<String> = self.descriptionLabel.textPresenter //{ self.button.clickedSignal.observe($0) } let rightButton: Presenter<() -> ()> = self.button.clickActionPresenter }

Hm…

Benefits?• Consistency

• Observability

• Testability

• Encapsulation

• Completeness

Examples?Popup Action

Navigation Property + Actions

UIKit Sinks + Presentables

Login Form Action + Operators

What’s next?

• RXMarbles (http://rxmarbles.com/)

• Reactive Cocoa sources - all here

Questions?

top related