Hacker News new | past | comments | ask | show | jobs | submit login

> In practice, you're going to have retain cycles, no? I mean I don't know where these four lines "live", but if we write them in a closure and ship them off to a sync/diff/runloop engine, unless we are quite careful, that sync engine is going to hold a great many strong references. Unless you intend this to be an IBAction definition, in which case...

There's a special structure that deals with IBAction called Action, for example:

        let press = Action<UIButton, UIColor, NoError> { button in
            return combineLatest(redSlider.producer, greenSlider.producer, blueSlider.producer)
                .throttle(0.5, onScheduler: QueueScheduler())
                .map({ r, g, b in UIColor(red: r, green: g, blue: b, alpha: 1.0) })
        }
        
        button.addTarget(press.unsafeCocoaAction, action: CocoaAction.selector, forControlEvents: UIControlEvents.TouchUpInside)
As to where you'd put the code: since this code snippet deals with declaring how a button should react to touch event, putting it in viewDidLoad will do. Now in my production app, most of the signal code are in viewDidLoad or viewWillAppear which doesn't have the retain cycle problem. If you want to "forward" the signal result to a sync/diff engine, then you'd extend the engine with ReactiveCocoa structure like `MutableProperty`, `SignalProducer`. Those structures would be responsible for feeding the data to the engine. After that its only a matter of binding you data signal to the extended strucutre.

In other words, coding in FRP is like trying to construct pipelines. Water (data) flows inside the pipelines, but you don't move the pipelines themsevles around, instead you build them in a way to direct the water to the intended destination. This is why most of the signal declaration is in the viewDidLoad and viewWillAppear.

> As long as the underlying Cocoa uses target-action, true compiler verification is impossible. Compiler verification checks something (these four lines) but it doesn't check that these lines actually run when the slider is moved in any way.

But it is possible to abstract away the dangerous code that rely on un-verifiable string declaration. For example in production app you'd have a lot image assets bundle with the app. In your view controller, you could naively load the image using string:

         imageView.image = UIImage(named: "cloud")
But anyone with decent experience with Cocoa should know that littering such code all over the codebase is not a good idea. Instead you could abstract the string portion away and put it in a struct and have the string as static member. When you load the image, it would be like so:

         imageView.image = UIImage(named: ImageAssets.cloud)
I'd say this code is way better than directly involving string. Although it is true that at the end of the day we are still using string thus true compiler verification is impossible, we reduce the points of failure to just one. As long as the string declaration in the struct is correct then everywhere else should be too.

From the above code example, ReactiveCocoa does abstract away the need to enter string characters into addTarget function. It is basically the same idea as the image example.

> Stopping in the debugger and trying to reason about these signal chains is complicated, because what we have here is a datastructure in memory, not lines of code I can step through

I would say the data structure explanation is not great. To me its more like constructing pipelines and water flow through it. There's operators that allow you to peek into the pipelines. It is true, however, that it's slightly more difficult, comparing to imperative, to debug for first timers as where you'd put the breakpoint is not immediately clear, but with any technologies there's always a trade off.

> This example does not account for threading, and in any nontrivial example you want to move between background and foreground a few times. It also does not deal with "splitting/merging" (multiple observers, etc.) and I suspect the intersection of those two features is a sharp edge.

Moving between threads is incredably easy:

          combineLatest(redSlider.producer, greenSlider.producer, blueSlider.producer)
                .delay(5, onScheduler: QueueScheduler())
                .map({ r, g, b in UIColor(red: r, green: g, blue: b, alpha: 1.0) })
                .observeOn(UISchedular())
In this example, the signal is delayed for 5 seconds off thread and performed "expansive" mapping off thread then brought back to main thread.



Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: