Alexey
Alexey

Reputation: 107

Swift combine: assign value in .sink, but can't use .assign

    $overallSecondsLeft
    .map
    { ti -> String? in
        let seconds = (ti.rounded(.up))
        if seconds > 0
        {
            return { String(format: "%02d:%02d", $0.0, $0.1) }(seconds.minutesAndSecondsOverHours)
        }
        return nil
    }
    .assign(to: \.timerText, on: bv)
    .store(in: &cancellables)

does not work. I mean - nothing happens. map returns string, but this string do not come in timerText.

Variant

    $overallSecondsLeft
    .map
    { ti -> String? in
        let seconds = (ti.rounded(.up))
        if seconds > 0
        {
            return { String(format: "%02d:%02d", $0.0, $0.1) }(seconds.minutesAndSecondsOverHours)
        }
        return nil
    }
    .sink{ bv.timerText = $0 }
    .store(in: &cancellables)

works correctly.

Environment:

class BView: UIView {
    ...
    var timerText: String? {
        get { ... }
        set { ... }
    }
    ...
}
guard let bv = view as? BView else { return }

Obviously, the question is: w..?

I found an advice to add .receive(on: RunLoop.main) before .assign, but it did not help.

Upvotes: 0

Views: 1932

Answers (1)

Christos Koninis
Christos Koninis

Reputation: 1688

The problem is that timerText variable is a computed property. The assign(to:on:) works on a KVO-compliant property of an object, and a computed property is not KVO compliant, if you remove the get/set it will work. Also please note that assign(to:on:) maintains a strong reference to object so you do not have to store the result to the cancellables.

Upvotes: 2

Related Questions