06 January 2016

You may come across this situation while working with RAC4:


You’ve created a Signal. You’ve setup a simple observer on the signal so that the values can be printed from it.

For some reason, no matter what you try, the results do not get processed from the Signal.


Here is a trivial sample signal.

func testSignal() -> Signal<String, NoError> {
    return Signal { observer in
        var i = 0
        while i < 10 {
            observer.sendNext(String(i))
            i++
        }
        observer.sendCompleted()
        return nil
    }
}

Here is a trivial observe action on the signal.

let printIt: String->() = {
    it in print("next \(next)")
}

testSignal().observeNext(printIt)

Can you answer what the output will be? Remember, whatever you have tried has failed to produce any result. So the answer is, you get no output here.


Is it a bug? No.

The reason is due to simple call order.

When observeNext() is reached in the chain, testSignal() has already completed because it blocked the current thread.

Making the signal values available requires that execution falls through to observeNext() before testSignal() completes.

There is nothing to observe if the signal blocks the observation of the signal.

This problem can be solved by redirecting the sendNext() calls to be asynchronous as in the following modified sample signal.

// Swiss cheese test signal: It has holes to fall through.
// dispatch_async() on the main thread is sufficient to allow falling through.
func testSignal() -> Signal<String, NoError> {
    return Signal { observer in
        dispatch_async(dispatch_get_main_queue()) {
            var i = 0
            while i < 10 {
                observer.sendNext(String(i))
                i++
            }
        }
        return nil
    }
}

The output now is:

next 0
next 1
next 2
next 3
next 4
next 5
next 6
next 7
next 8
next 9

If you were having trouble understanding when individual operations are getting called in a signal chain, hopefully this post has helped you get past that. Consideration of sync vs async is rampant in iOS and OS X development and extremely important to recognize.

In simple terms, either an operation is blocking or it allows falling through to the next operation.

Libraries like RAC4 that help to make creating software more efficient by leveraging alternative concurrency paradigms especially require this discernment.



blog comments powered by Disqus