#mbltdev: Разработка на swift (ash furrow)

36
Functional Reactive Programming in Swift Ash Furrow

Upload: e-legion

Post on 26-Jun-2015

969 views

Category:

Mobile


4 download

DESCRIPTION

#MBLTdev: Конференция мобильных разработчиков Спикер: Ash Furrow iOS-разработчик, Artsy http://mbltdev.ru/

TRANSCRIPT

Page 1: #MBLTdev: Разработка на Swift (Ash Furrow)

Functional Reactive Programming in Swift

Ash  Furrow

Page 2: #MBLTdev: Разработка на Swift (Ash Furrow)

Agenda

1. Func'onal  reac've  programming  uses  a  concept  call  “signals”  

2. Reac'veCocoa  uses  signals  to  reduce  mutable  state  

3. Ge>ng  started  is  easy

Page 3: #MBLTdev: Разработка на Swift (Ash Furrow)

Signals

Page 4: #MBLTdev: Разработка на Swift (Ash Furrow)

Signals• At  the  core  of  FRP  are  signals  

• Signals  send  values  over  'me,  un'l  they  complete  or  error  out  

• A  signal  never  sends  anything  aGer  comple'ng  or  erring    

• A  signal  either  completes,  or  errors  out,  but  never  both  

• A  signal  has  no  concept  of  a  “current  value”  or  “past  values”  

• It’s  like  a  pipe

Page 5: #MBLTdev: Разработка на Swift (Ash Furrow)

Signals

• Signals  can  be  chained  to  transform  the  values  that  they  send  

• This  is  core  to  FRP:  data  transforma'on  of  values  sent  over  'me  

• In  math  terms,  it’s  f(g(y))

Page 6: #MBLTdev: Разработка на Swift (Ash Furrow)

ReactiveCocoa

Page 7: #MBLTdev: Разработка на Swift (Ash Furrow)

• Reac'veCocoa  is  a  framework  developed  by  GitHub  

• Reac'veCocoa  is  an  implementa'on  of  FRP  on  iOS/OS  X  

• It’s  currently  being  revamped  with  SwiG  to  version  3.0

Page 8: #MBLTdev: Разработка на Swift (Ash Furrow)

Signals• Signals  are  typically  built  on  KVO  

• They  can  also  be  created  manually  

• Crea'ng  a  signal  is  easy  

• RACObserve()  

• Wraps  a  dynamic  property  

• Sends  a  new  value  for  updated  property  values

Page 9: #MBLTdev: Разработка на Swift (Ash Furrow)

Signals

• Subscribe  to  a  signal  to  perform  side-­‐effects  when  it  sends  new  values  

• Or  use  bindings  (later)

Page 10: #MBLTdev: Разработка на Swift (Ash Furrow)

public func RACObserve(target: NSObject!, keyPath: String) -> RACSignal { return target.rac_valuesForKeyPath(keyPath, observer: target) }

github.com/AshFurrow/Swift-RAC-Macros

Page 11: #MBLTdev: Разработка на Swift (Ash Furrow)

let signal = RACObserve(object, "number")

signal.subscribeNext { (number) -> Void in println("Received \(number)") }

Page 12: #MBLTdev: Разработка на Swift (Ash Furrow)

Signal Operators

• Signal  operators  transform  the  values  sent  by  signals  

• These  are  func'ons  on  a  signal  that  return  a  new  signal

Page 13: #MBLTdev: Разработка на Swift (Ash Furrow)
Page 14: #MBLTdev: Разработка на Swift (Ash Furrow)

Map

• Mapping  performs  a  value  transforma'on  on  the  given  signal  

• It  “maps”  each  value  sent  along  the  signal  to  a  new  value  

• It  then  passes  that  new  value  along,  crea'ng  a  new  signal  

• This  is  the  canonical  value  transforma'on

Page 15: #MBLTdev: Разработка на Swift (Ash Furrow)

let signal = RACObserve(object, “number")

signal.map { (number) -> AnyObject! in return "\(number)" }.subscribeNext { (string) -> Void in println("Received \(string)") }

Page 16: #MBLTdev: Разработка на Swift (Ash Furrow)

let signal = RACObserve(object, “person")

signal.map { (object) -> AnyObject! in return (object as Person).name }.subscribeNext { (name) -> Void in println(“name: \(name)") }

Page 17: #MBLTdev: Разработка на Swift (Ash Furrow)

func toName(person: AnyObject!) -> AnyObject! { return (person as Person).name }

let signal = RACObserve(object, “person")

signal.map(toName).subscribeNext { (name) -> Void in println(“name: \(name)") }

Page 18: #MBLTdev: Разработка на Swift (Ash Furrow)

Filter

• Filtering  allows  values  that  pass  some  test  to  “pass  through”

Page 19: #MBLTdev: Разработка на Swift (Ash Furrow)

someNumberSignal.filter { (object) -> Bool in return (object as NSNumber) > 5 }.subscribeNext { (object) -> Void in return "The number is \(object)" }

Page 20: #MBLTdev: Разработка на Swift (Ash Furrow)

Bindings

• Bindings  can  bind  a  property  to  the  latest  value  sent  on  a  signal  

• Bindings  are  typically  created  with  the  RAC  func'on  

• All  bindings  created  with  the  RAC  func'on  are  one-­‐way  

• Bindings  are  the  secret  sauce  that  hold  apps  together

Page 21: #MBLTdev: Разработка на Swift (Ash Furrow)

public struct RAC { var target: NSObject var keyPath: String var nilValue: AnyObject? public init(_ target: NSObject, _ keyPath: String, nilValue: AnyObject? = nil) { self.target = target self.keyPath = keyPath self.nilValue = nilValue } func assignSignal(signal : RACSignal) -> RACDisposable { return signal.setKeyPath(self.keyPath, onObject: self.target, nilValue: self.nilValue) } }

infix operator <~ {} public func <~ (rac: RAC, signal: RACSignal) -> RACDisposable { return signal ~> rac }

public func ~> (signal: RACSignal, rac: RAC) -> RACDisposable { return rac.assignSignal(signal) }

github.com/AshFurrow/Swift-RAC-Macros

Page 22: #MBLTdev: Разработка на Swift (Ash Furrow)

RAC(textField, "text") <~ RACObserve(self, "someString")

Page 23: #MBLTdev: Разработка на Swift (Ash Furrow)

Derived State

• State  is  avoided  in  Reac'veCocoa,  but  is  unavoidable  in  Cocoa  

• Instead  of  hacky  workarounds,  we  derive  the  state  from  signals  

• Similar  to  the  last  example’s  enabled  state  binding

Page 24: #MBLTdev: Разработка на Swift (Ash Furrow)

Other Operators

• combineLatest()  

• takeUn'l()  

• scheduleOn()  

• thro_le()  

• not(),  and(),  or()

Page 25: #MBLTdev: Разработка на Swift (Ash Furrow)

Getting Started

Page 26: #MBLTdev: Разработка на Swift (Ash Furrow)

Getting Started

• Ge>ng  started  with  Reac'veCocoa  is  easy  

• Install  Reac'veCocoa  in  your  project  as  a  submodule  

• Switch  to  the  swiG-­‐development  branch

Page 27: #MBLTdev: Разработка на Swift (Ash Furrow)

Getting Started

• Start  by  replacing  KVO  methods  with  RACObserve  

• Use  subscribeNext()  or  doNext()  for  side-­‐effects  

• Start  looking  for  opportuni'es  to  replace  state  with  signals

Page 28: #MBLTdev: Разработка на Swift (Ash Furrow)

Getting Started

• When  create  a  property,  ask  yourself  if  a  signal  would  be  appropriate  

• Is  it  important  to  know  the  value  of  the  property  aGer  it’s  set?  

• Are  side-­‐effects  performed  when  it’s  changed?

Page 29: #MBLTdev: Разработка на Swift (Ash Furrow)

Demo github.com/AshFurrow/MBLTDev

Page 30: #MBLTdev: Разработка на Swift (Ash Furrow)

Demo

• No'ce  subscribeNext:  is  used  for  side-­‐effects  

• Cocoa  Touch  isn’t  built  on  FRP,  so  we  need  side-­‐effects  

• Network  results  are  delivered  on  a  background  scheduler  

• Use  deliverOn()  to  reschedule  them

Page 31: #MBLTdev: Разработка на Swift (Ash Furrow)

github.com/artsy/eidolon

Page 32: #MBLTdev: Разработка на Swift (Ash Furrow)

Eidolon• Completely  open  source  iOS  8  SwiG  app  wri_en  using  Reac'veCocoa  

• Lots  of  examples  of  its  use  

• Observing  model  proper'es  

• User  interface  changes  

• Networking  code  

• S'll  a  work-­‐in-­‐progress

Page 33: #MBLTdev: Разработка на Swift (Ash Furrow)

Getting Started

• Start  slowly  

• You’re  responsible  for  this  decision  

• Be  prepared  to  answer  ques'ons  

• There  is  a  community  to  support  you

Page 34: #MBLTdev: Разработка на Swift (Ash Furrow)

Wrap Up

1. Func'onal  reac've  programming  uses  a  concept  call  “signals”  

2. Reac'veCocoa  uses  signals  to  reduce  mutable  state  

3. Ge>ng  started  is  easy

Page 35: #MBLTdev: Разработка на Swift (Ash Furrow)

http://leanpub.com/iosfrp

Page 36: #MBLTdev: Разработка на Swift (Ash Furrow)

@ashfurrow ashfurrow.com