Search code examples
iosswiftmvvmuiimageviewrx-swift

How to bind image to UIImageView with rxswift?


I have viewModel:

class EditFoodViewViewModel {
    private var food: Food

    var foodImage = Variable<NSData>(NSData())

    init(food: Food) {
        self.food = food
        self.foodImage.value = food.image!
    }
}

And ViewController:

class EditFoodViewController: UIViewController {
    public var food: EditFoodViewViewModelType?
    @IBOutlet weak var foodThumbnailImageView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()

        guard let foodViewModel = food else { return }
        foodViewModel.foodImage.asObservable().bind(to: foodThumbnailImageView.rx.image).disposed(by: disposeBag)
  }
}

In the last line of viewController (where my UIImageView) a get error:

Generic parameter 'Self' could not be inferred

How to solve my problem? How to set image to imageView with rxSwift?


Solution

  • Almost invariably, when you see the error: "Generic parameter 'Self' could not be inferred", it means that the types are wrong. In this case you are trying to bind an Observable<NSData> to an Observable<Image?>.

    There's a few other issues with your code as well.

    • it is very rare that a Subject type should be defined with the var keyword and this is not one of those rare times. Your foodImage should be a let not a var.

    • Variable has been deprecated; don't use it. In this case, you don't even need a subject at all.

    • NSData is also inappropriate in modern Swift. Use Data instead.

    Based on what you have shown here, I would expect your code to look more like this:

    class EditFoodViewViewModel: EditFoodViewViewModelType {
        let foodImage: Observable<UIImage?>
    
        init(food: Food) {
            self.foodImage = Observable.just(UIImage(data: food.image))
        }
    }
    
    class EditFoodViewController: UIViewController {
    
        @IBOutlet weak var foodThumbnailImageView: UIImageView!
        public var food: EditFoodViewViewModelType?
        private let disposeBag = DisposeBag()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            guard let foodViewModel = food else { return }
            foodViewModel.foodImage
                .bind(to: foodThumbnailImageView.rx.image)
                .disposed(by: disposeBag)
        }
    }