iosswiftrx-swiftrx-cocoa

configureCell is not triggered when I update a datasource using RxDatasources


I am having a behavior relay in my view model that is used as a source of data. Its defined like this:

var posts: BehaviorRelay<[PostModel]>

It is initialized with data through the network, and it initializes tableView normally when I bind data to it.

Now, if I try to change say, the like status of a post here, like this (this is also in my view model):

private func observeLikeStatusChange() {
        
        self.changedLikeStatusForPost
            .withLatestFrom(self.posts, resultSelector: { ($1, $0) })
            .map{ (posts, changedPost) -> [PostModel] in
                //...
                var editedPosts = posts
                editedPosts[index] = changedPost // here data is correct, index, changedContact
                return editedPosts
            }
            .bind(to: self.posts)
            .disposed(by: disposeBag)
    }

So with this, nothing happens. If I remove the element from editedPosts, the tableView updates correctly and removes the row.

PostModel struct conforms to Equatable, and it requires all properties to be the same at the moment.

In my view controller, I create datasource like this:

tableView.rx.setDelegate(self).disposed(by: disposeBag)
 let dataSource = RxTableViewSectionedAnimatedDataSource<PostsSectionModel>(
            configureCell: { dataSource, tableView, indexPath, item in
             //...
                return postCell
            })
        
        postsViewModel.posts
            .map({ posts in
                let models = posts.map{ PostCellModel(model: $0) }
                return [PostsSectionModel(model: "", items: models)]
            }) // If I put debug() here, this is triggered and I get correct section model with correct values
            .bind(to: self.tableView.rx.items(dataSource: dataSource))
            .disposed(by: disposeBag)

So, as I said, I am getting correct values, but configureCell is not triggered. What I am doing wrong here?

EDIT:

Here is PostCellModel:

import Foundation

import RxDataSources

typealias PostsSectionModel = AnimatableSectionModel<String, PostCellModel>


struct PostCellModel : Equatable, IdentifiableType {
    
    static func == (lhs: PostCellModel, rhs: PostCellModel) -> Bool {
        
        return lhs.model.id == rhs.model.id
    }
    
    var identity: Int {
        return model.id
    }
    var model: PostModel
}

and a PostModel:

 struct PostModel: Codable, CellDataModel, Equatable {
    static func == (lhs: PostModel, rhs: PostModel) -> Bool {
       return
        lhs.liked == rhs.liked &&
        rhs.title == lhs.title &&
        
        lhs.location == rhs.location &&
        lhs.author == rhs.author &&
       
        lhs.created == rhs.created
    }
    
    let id: Int
    let title: String
    let location: String?
    let author: String
    let created: Int
    let liked:Bool
}

Solution

  • You have defined your Equatable conformance incorrectly in the PostCellModel. Because of that, the system is unable to tell whether a cell model has changed... Remove your manually defined ==(lhs:rhs:) and let the system generate them for you and you should be fine...

    typealias PostsSectionModel = AnimatableSectionModel<String, PostCellModel>
    
    struct PostCellModel : Equatable, IdentifiableType {
        var identity: Int {
            return model.id
        }
        var model: PostModel
    }
    
    struct PostModel: Codable, CellDataModel, Equatable {
        let id: Int
        let title: String
        let location: String?
        let author: String
        let created: Int
        let liked:Bool
    }