2

I'm trying to observe array change and bind it to the image of the button.

if the array is empty. set picture of an empty cart.

else set image of a cart.

so what I did was :

let x = itemsArray.observeNext { [weak self] (v) in
    let image = v.source.isEmpty ? #imageLiteral(resourceName: "emptyCart") : #imageLiteral(resourceName: "cart")
    self?.orderItemsButton.setImage(image, for: .normal)
}

But if I do use this way I must dispose x in viewWillDisappear or something like that...

What is the right way to do it?

chwarr
  • 6,777
  • 1
  • 30
  • 57
Marry G
  • 377
  • 1
  • 3
  • 16

2 Answers2

4

You can replace observation with a binding. In that case disposable is handled by the framework itself (ReactiveKit).

All you need to do is this:

itemsArray.bind(to: self) { me, array in
    let image = array.source.isEmpty ? #imageLiteral(resourceName: "emptyCart") : #imageLiteral(resourceName: "cart")
    me.orderItemsButton.setImage(image, for: .normal)
}

You can find more info about bindings in the documentation: https://github.com/ReactiveKit/ReactiveKit#bindings

I would almost always recommend doing bind(to:) instead observeNext. It automatically handles weak self, disposing and also ensures that the object is updated on the correct thread.


As a bonus, you can also solve this problem by mapping the array signal to an image signal and then binding that to the button (assuming you are using ReactiveKit+Bond).

itemsArray
  .map { $0.source.isEmpty ? #imageLiteral(resourceName: "emptyCart") : #imageLiteral(resourceName: "cart") }
  .bind(to: orderItemsButton.reactive.image)
Srđan Rašić
  • 1,597
  • 15
  • 23
1

i think easy way can be something like this

  var itemsArray: [Any] = [] {
        didSet {
            guard oldValue != itemsArray else { return }
            let image = itemsArray.isEmpty ? #imageLiteral(resourceName: "emptyCart") : #imageLiteral(resourceName: "cart")
            orderItemsButton.setImage(image, for: .normal)
        }
    }

everytime you set itemsArray didSet will be called and change orderItemsButton's image if needed.

EDIT:

base on what you said in comments you can use delegate

protocol CartDelegate: class {
    func setCartImage(isEmpty: Bool)
}


class ViewController: UIViewController, CartDelegate {

    var orderItemsButton: UIButton!
    var someRandomClass: SomeRandomClass!

    func setCartImage(isEmpty: Bool) {
        if isEmpty {
            // set image to empty cart
            orderItemsButton.setImage(nil, for: .normal)
        } else {
            // set image to full cart
            orderItemsButton.setImage(nil, for: .normal)
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // initate and set delegate to self
        someRandomClass = SomeRandomClass()
        someRandomClass.delegate = self
    }
}


class SomeRandomClass {
    weak var delegate: CartDelegate?

    var itemsArray: [Any] = [] {
        didSet {
            delegate?.setCartImage(isEmpty: itemsArray.isEmpty)
        }
    }
}
Mohammadalijf
  • 1,387
  • 9
  • 19