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

Functional Reactive Programming in Swift

Ash Furrow
October 28, 2014

Functional Reactive Programming in Swift

Take a look at how functional reactive programming works using ReactiveCocoa and Swift. See how to use existing Objective-C APIs with Swift and examine common concepts in functional reactive programming like data transformation, filtering, and binding. Finally, get some resources for how to begin your journey to becoming a ReactiveCocoa expert.

Presented at MBLTDev: http://mbltdev.ru
Sample code: https://github.com/AshFurrow/MBLTDev

Ash Furrow

October 28, 2014
Tweet

More Decks by Ash Furrow

Other Decks in Programming

Transcript

  1. Functional Reactive
    Programming in Swift
    Ash  Furrow

    View full-size slide

  2. 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

    View full-size slide

  3. 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

    View full-size slide

  4. 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))

    View full-size slide

  5. ReactiveCocoa

    View full-size slide

  6. • 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

    View full-size slide

  7. 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

    View full-size slide

  8. Signals
    • Subscribe  to  a  signal  to  perform  side-­‐effects  when  it  sends  new  values  
    • Or  use  bindings  (later)

    View full-size slide

  9. public func RACObserve(target: NSObject!, keyPath: String) -> RACSignal {
    return target.rac_valuesForKeyPath(keyPath, observer: target)
    }
    github.com/AshFurrow/Swift-RAC-Macros

    View full-size slide

  10. let signal = RACObserve(object, "number")
    signal.subscribeNext { (number) -> Void in
    println("Received \(number)")
    }

    View full-size slide

  11. Signal Operators
    • Signal  operators  transform  the  values  sent  by  signals  
    • These  are  func'ons  on  a  signal  that  return  a  new  signal

    View full-size slide

  12. 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

    View full-size slide

  13. let signal = RACObserve(object, “number")
    signal.map { (number) -> AnyObject! in
    return "\(number)"
    }.subscribeNext { (string) -> Void in
    println("Received \(string)")
    }

    View full-size slide

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

    View full-size slide

  15. 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)")
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  18. 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

    View full-size slide

  19. 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

    View full-size slide

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

    View full-size slide

  21. 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

    View full-size slide

  22. Other Operators
    • combineLatest()  
    • takeUn'l()  
    • scheduleOn()  
    • thro_le()  
    • not(),  and(),  or()

    View full-size slide

  23. Getting Started

    View full-size slide

  24. 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

    View full-size slide

  25. 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

    View full-size slide

  26. 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?

    View full-size slide

  27. Demo
    github.com/AshFurrow/MBLTDev

    View full-size slide

  28. 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

    View full-size slide

  29. github.com/artsy/eidolon

    View full-size slide

  30. 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

    View full-size slide

  31. Getting Started
    • Start  slowly  
    • You’re  responsible  for  this  decision  
    • Be  prepared  to  answer  ques'ons  
    • There  is  a  community  to  support  you

    View full-size slide

  32. 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

    View full-size slide

  33. http://leanpub.com/iosfrp

    View full-size slide

  34. @ashfurrow
    ashfurrow.com

    View full-size slide