Get only one value from Observable - swift

I am starting in RxSwift, coming from ReactiveCocoa. I have a conceptual question.
Let's say I have a value I want to observe over time, e.g. a temperatue. So there are many cases and places I subscribe this value to react on changes. No problem!
But there are also use cases when I just need the latest value e.g.:
if temperatue > 5 {
// do something
}
So i just want to do a decision/operation on that value or at least based on that value. That drives me close to using a shareReplay observable. But would I need to subscribe that value even when I just want to use it once?
Or is this approach wrong at all? How would I do that use case (value over time vs. accessing last value only once)? Would I need to sources, one hot one cold?

Use Variable:
class SomeClass {
let temperature = Variable<Int>(50)
func doSomething() {
if temperature.value > 50 {
print("something")
}
}
func subscribeToTemperature() {
temperature.asObservable.subscribeNext { t in
print("Temperature now is \(t)")
}.addDisposableTo(bag)
}
func setTemperature() {
temperature.value = 20
}
func observeTemperature(t: Observable<Int>) {
t.bindTo(temperature).addDisposableTo(bag)
}
}

Related

How to make a proper reactive extension on Eureka SelectableSection

This is my first question to the StackOverflow community so excuse me if I'm doing something wrong.
1. What I'm trying to achieve
Basically, I want to make a custom reactive wrapper around Eureka's SelectableSection class in order to observe the value of the selected row when it is changed. I'm thinking to get this data from the onSelectSelectableRow closure which is called every time a row is selected.
2. What I've tried to do for that
Actually, I've got this working but it's not a generic use of the custom wrapper, here is the example that works but only when I specify the row and its value type, for example ListCheckRow<Int>.
extension SelectableSection: ReactiveCompatible {}
extension Reactive where Base : SelectableSection<ListCheckRow<Int>> {
var selectedValue: Observable<Base.SelectableRow.Cell.Value?> {
return Observable.create { observer in
self.base.onSelectSelectableRow = {cell, row in
observer.onNext(row.value)
}
return Disposables.create {
observer.onCompleted()
}
}
}
}
This works fine and as I expected but when it comes to something more generic like the next code example, I get an error saying that: "Cannot assign to property: 'base' is a 'let' constant"
extension SelectableSection: ReactiveCompatible {}
extension Reactive where Base : SelectableSectionType {
var selectedValue: Observable<Base.SelectableRow.Cell.Value?> {
return Observable.create { observer in
self.base.onSelectSelectableRow = {cell, row in // Error: Cannot assign to property: 'base' is a 'let' constant
observer.onNext(row.value)
}
return Disposables.create {
observer.onCompleted()
}
}
}
}
Any help will be much appreciated, thanks. 🙏
The fundamental problem here is that SelectableSectionType is a protocol that isn't restricted to class types and Reactive assumes that Base is a class (or otherwise is not going to be modified by the observable creation.)
I think the most generic you can make this is something like:
extension Reactive {
func selectedValue<Row, T>() -> Observable<T?> where Base: SelectableSection<Row>, Row: SelectableRowType, T == Row.Cell.Value {
Observable.create { [base] observer in
base.onSelectSelectableRow = { cell, row in
observer.onNext(row.value) // this is problematic. See below.
}
return Disposables.create {
observer.onCompleted() // this is wrong. See below.
}
}
}
}
The biggest problem with the above though is that if you subscribe to the resulting Observable more than once or create more than one Observable using this computed property, all but the last subscription will silently fail. The simple way to fix this is to always remember to share any result but that's rather error prone.
The way to fix this would be to associate a Subject with each SelectableSection, but you can't modify the class, so what are we to do?
Here's a solution:
extension Reactive {
func selectedValue<Row, T>() -> Observable<T?> where Base: SelectableSection<Row>, Row: SelectableRowType, T == Row.Cell.Value {
Observable.create { [base] observer in
if let block = selectableSections.first(where: { $0.section === base }) {
let subject = block.subject as! PublishSubject<T?>
return Disposables.create(
block.disposable.retain(),
subject.subscribe(observer)
)
}
else {
let subject = PublishSubject<T?>()
let block = SelectableSectionBlock(
section: base,
subject: subject,
disposable: RefCountDisposable(disposable: Disposables.create {
selectableSections.removeAll(where: { $0.section === base })
})
)
base.onSelectSelectableRow = { cell, row in
subject.onNext(row.value)
}
selectableSections.append(block)
return Disposables.create(
block.disposable,
subject.subscribe(observer)
)
}
}
}
}
private struct SelectableSectionBlock {
let section: Section
let subject: Any
let disposable: RefCountDisposable
}
private var selectableSections = [SelectableSectionBlock]()
The selectableSections array stores a Subject and RefCountDisposable for each SelectableSection.
Whenever an Observable is created, or subscribed to...
if it's the first time working with this section, it will create a Subject and RefCountDisposable assign the onSelectSelectableRow to send a next event to the subject and store the subject in the array.
otherwise it will find the subject and disposable associated with this Section and retain the disposable.
Once it has the subject and disposable from above, it will subscribe the new observer to the subject and return a new Disposable that will remove that subscription and decrement the ref-count when the time comes.
Yes this is quite a bit more complex than the simple assignment case, but it's the right thing to do.
As for calling onCompleted() inside the disposable closure. By the time the closure is called, the observer has already emitted an onCompleted/onError event, or the observer has stopped listening to the observable. So this event will never be seen.

Testing a class which preserves its state in private variables

I am writing unit tests for my class. This class preserves its state in some private variables (which I don't want to expose publicly). So the scenario is:
If I call a method, the first time it will keep that state in private properties and call a delegate method with some result.
When I call the same method a second time, the output will be different on the basis of the previous input.
I want to cover all the cases in my tests.
One easy way is to change my private properties to public so that I can mock the previous input in unit test.
The other way is to call the same method with different inputs in the same test twice. Where the first call will keep the state and the next call will be the actual test.
But both these ways seem awkward to me, and I am not sure of the best one.
What is the best way to write unit test for this class?
protocol ZoneUpdateDetectorOutput: class {
func updateZoneState(_ state: ZoneState)
}
class ZoneUpdateDetector {
var zoneChangeTimer: TimerProtocol?
weak var delegate: ZoneUpdateDetectorOutput?
private var previousZoneState: ZoneState?
private var expectedZoneState: ZoneState?
private func updateZoneState() {
// If `expectedZoneState` is not equal to `previousZoneState` then `delegate` will be called
// Otherwise it will just skip
if expectedZoneState != previousZoneState {
delegate?.updateZoneState(expectedZoneState!)
previousZoneState = expectedZoneState
}
}
private func runNotifyZoneStateTimer() {
guard zoneChangeTimer?.isValid() == false else {
return
}
zoneChangeTimer?.start(timeInterval: 5,
onFire: { [weak self] in
guard let strongSelf = self else {
return
}
// On timer fire, it will try to update the state
strongSelf.updateZoneState()
})
}
// When zone changes, this method is invoked
// I basically want to test this method
func zoneStateChanged(_ state: ZoneState) {
expectedZoneState = state
if state != .inZone {
runNotifyZoneStateTimer()
} else {
zoneChangeTimer?.stop()
}
}
}
You should never be testing internal state; you should only test externally (publically) visible behaviour. That way, you can change implementation details of your class without breaking any contracts, and thus without breaking any tests.
So the second option is the preferred one.
After researching and discussing with some experts, I come up with the solution that if we want to test a class which preserve it's state then the functionality which is preserving the state should go under a separate class. Which will serve the same purpose as setting the variables as private. So, ZoneUpdateDetector should have a dependency for example: ZoneUpdateStatePreserver and it should keep the state which was previously inside ZoneUpdateDetector

Using an instance in a function

I’m new to Swift so I’ve been using the Swift Playgrounds app. On level 2 “Two Experts”, I initialized two experts:
let expert1 = Expert()
let expert2 = Expert()
What I wanted to do was create a function and pass whichever instance into it, access it’s methods etc, something like:
func actions(who: Item, distance: Int, turn: String) {
for 0 to distance {
who.moveforward()
}
ff turn == “Left” {
who.turnleft()
} else if turn == “Right” {
who.turnright()
}
}
Where who is expert1 or expert2.
I couldn’t find a way of doing this so had to write the same actions twice:
Func actions(who: String, distance: Int, turn:String) {
if who == “expert1” {
for 0 to distance {
expert1.moveforward()
} Etc
if who == “expert2” {
for 0 to distance {
expert2.moveforward()
} Etc
Is there a way of passing an instance into a function then perform certain actions if it’s of a particular class?
Since your experts is of type Expert, then the who parameter in your actions method should be of type Expert, if I understand the code correctly. Then you don't need two functions for each of the Experts. Let me know if I understood you correctly, and if it worked out.
Update
#Alexander mentioned that you can also have these methods in an extension on Expert, like so:
extension Expert {
func actions(distance: Int, turn: String) {
// Add method code here
}
}
When adding the method in an extension, every Expert object can use the method. So you could write expert1.actions(1, "Left") or something like that. Here's a link to the official Swift Programming Language guide about extensions.

How to use a Publish subject to observe a variable's value?

I'm new to using RxSwift framework, I'm actually learning and trying to understand the basics and I would like some help from you please.
private func observeCurrentIndex() -> Observable<Int> {
return Observable<Int>.create { (observer) -> Disposable in
observer.onNext(self.currentIndex)
return Disposables.create()
}
}
Here I've created an observable on currentIndex which is an int. When I subscribe to it, I get only the first value of currentIndex which is 2. Is it not supposed to notify me whenever currentIndex changes(just like a KVO would)?
override func viewDidLoad() {
super.viewDidLoad()
observeCurrentIndex()
.subscribe(onNext: { (valeur) in
print("new value \(valeur)")
})
.addDisposableTo(disposeBag)
}
To be notified each time currentIndex changes value, I've been told that I have to use a publishSubject for that.
#IBAction func increaseAction(_ sender: UIButton) {
if currentIndex <= kMaxIndex {
currentIndex = currentIndex + 1
}
}
Could someone indicate to me where and how to do this? Thanks in advance.
Usually, Subjects are used to bridge an imperative API to reactive world. More information on how to use subject can be found here.
There are a couple solution to observe a variable evolution using RxSwift's primitives
Using KVO
class WithIndex: NSObject {
dynamic var currentIndex: Int
func observeCurrentIndex() -> Observable<Int> {
return instance.rx.observe(Int.self, "currentIndex")
}
#IBAction func increaseAction(_ sender: UIButton) {
if currentIndex <= kMaxIndex {
currentIndex = currentIndex + 1
}
}
}
The drawback with this solution is that WithIndex needs to inherit from NSObject for KVO to be available.
Using Variable
class WithIndex {
let currentIndex: Variable<Int>
func observeCurrentIndex() -> Observable<Int> {
return currentIndex.asObservable()
}
#IBAction func increaseAction(_ sender: UIButton) {
if currentIndex.value <= kMaxIndex {
currentIndex.value = currentIndex.value + 1
}
}
}
This one is more pratical. You can then set currentIndex's value using currentIndex.value = 12 and observe using currentIndex.asObservable().subscribe(...).
Variable is a simple wrapper around BehaviorSubject and will send a .next event every time variable's value changes.
I come from RxJS, but I think what you really need is a ReplaySubject.
The first code you provided, you're just creating an observable that only returns 1 value. The code inside Observable.create just gets executed once every time someone .subscribe()s on it.
A publish is more meant to share a subscription between many subscribers... The perfect case for that is that if you need a specific info gathered from one server to be used in many places in your app... You don't want to spam the server with so many requests, so you just make one request, publish that and observers will subscribe to that published stream.
A ReplaySubject (or BehaviourSubject, but then you need to know the initial value when you initialize it) is more in the line of what you want: It's both an Observable and an Observer, an object where other observers can subscribe to, and every time you call .onNext() to it, all subscribers will get a new value.
Rx can't do magic, it doesn't know when/how you are editing your variables. So you will need to create a ReplaySubject of length 1 in your object, and return that to subscribers. Then track on your code whenever your currentIndex changes, call the onNext method on that ReplaySubject.

What's the best Swift pattern for returning a pending PromiseKit promise if one is already in running?

I have some expensive promises that get called in different spots. Ideally, I'd like to just chain off an existing in-flight promise (with an optional force), so I find myself doing something like this:
class Expensive {
var fooPromise : Promise<Foo>?
var barPromise : Promise<Bar>?
func doExpensiveFoo(force: bool = false) -> Promise<Foo> {
if let existing = fooPromise where existing.pending || (existing.fufilled && !force) {
// Return the existing promise
return existing
}
// Start a new Foo
return firstly {
// ...
}
}
func doExpensiveBar(force: bool = false) -> Promise<Bar> {
if let existing = barPromise where existing.pending || (existing.fufilled && !force) {
// Return the existing promise
return existing
}
// Start a new Bar
return firstly {
// ...
}
}
}
But that feels like a fair amount of boiler-plate (a local variable for each promise, and the existing chunk at the start of each function), so I'm wondering if anyone has seen a good pattern for abstracting away the variables and wrapper?
To borrow a term from Python, I'm looking for a decorator that would hide all that. Something like:
class Expensive {
private func startFoo() -> Promise<Foo> {
return firstly {
//..
}
}
public doExpensiveFoo = wrapExpensive(startFoo)
}
Any suggestions, or should I look at rolling my own?
I'm no expert, but this pattern worked for me:
private var fooPromise : Promise<Foo>?
func doExpensiveFoo() -> Promise<Foo> {
if let fooPromise = self.fooPromise, fooPromise.isPending {
// return the pending promise
return fooPromise
}
// reassign a newly created promise
fooPromise = firstly {
// do your thing
...
}
return fooPromise!
}
What I like about this pattern is that the method handles pending state internally, and that the promise automatically re-executes if called after it is finished. This allows callers to be ignorant of the internal mechanism or the state of the promise. Obviously, if you need to caller to be part of the decision, then keep the "force" flag approach.
I do not see any common base of Foo and Bar in your example. But even if they would have one Swift still does not support covariance on generic type parameters. At first you would need to create a common protocol for both types. Maybe this helps you to get on track:
Storing generic objects in Swift Array