簡體   English   中英

使用 RxDatasources 綁定到數據源

[英]Binding to a datasource using RxDatasources

我有一個從服務器獲取的模型列表,基本上我得到了以下數組:

struct ContactModel: Codable, Equatable {
static func == (lhs: ContactModel, rhs: ContactModel) -> Bool {
    return lhs.name == rhs.name &&
    lhs.avatar == rhs.avatar &&
    lhs.job == rhs.job &&
    lhs.follow == rhs.follow
}

let id: Int
let name: String
let avatar:String?
let job: JobModel?
let follow:Bool

enum CodingKeys: String, CodingKey {
    case id, name, avatar, job, follow
}

}

所以我想在我的tableview中顯示一個聯系人列表。

現在我也有這個結構,它是這個 model 的包裝器:

struct ContactCellModel : Equatable, IdentifiableType {
    
    static func == (lhs: ContactCellModel, rhs: ContactCellModel) -> Bool {
        
        return lhs.model == rhs.model
    }
    
    var identity: Int {
        return model.id
    }
    
    var model: ContactModel
    var cellIdentifier = ContactTableViewCell.identifier
}

我想做的是使用RxDatasources創建數據源,並綁定到它,如下所示(ContactsViewController.swift):

let dataSource = RxTableViewSectionedAnimatedDataSource<ContactsSectionModel>(
            configureCell: { dataSource, tableView, indexPath, item in
                if let cell = tableView.dequeueReusableCell(withIdentifier: item.cellIdentifier, for: indexPath) as? BaseTableViewCell{
                    cell.setup(data: item.model)
                    return cell
                }
                
                return UITableViewCell()
                
            })

但我不確定我應該做什么。 我試過這樣的事情:

Observable.combineLatest(contactsViewModel.output.contacts, self.contactViewModel.changedStatusForContact)
            .map{ (allContacts, changedContact) -> ContactsSectionModel in
               
               //what should I return here?
            }.bind(to: dataSource)

我使用combineLatest ,因為我還有一個可觀察的( self.contactViewModel.changedStatusForContact )通知某個聯系人何時更改(當您點擊聯系人單元格上的某個按鈕時會發生這種情況)。

那么我應該從上面的.map 返回什么才能成功綁定到先前創建的dataSource

您必須更換已更改的聯系人; 所有已更改的聯系人,但您不能這樣做,因為您沒有跟蹤所有聯系人,僅跟蹤最近的一個。 所以你不能在 map 中做到這一點。 您需要改用scan

我對你沒有發布的代碼做了很多假設,所以下面是一個可編譯的例子。 如果您的類型不同,則必須進行一些更改:

func example(contacts: Observable<[ContactModel]>, changedStatusForContact: Observable<ContactModel>, tableView: UITableView, disposeBag: DisposeBag) {
    let dataSource = RxTableViewSectionedAnimatedDataSource<ContactsSectionModel>(
        configureCell: { dataSource, tableView, indexPath, item in
            if let cell = tableView.dequeueReusableCell(withIdentifier: item.cellIdentifier, for: indexPath) as? BaseTableViewCell {
                cell.setup(data: item.model)
                return cell
            }
            return UITableViewCell() // this is quite dangerious. Better would be to crash IMO.

        })

    let contactsSectionModels = Observable.combineLatest(contacts, changedStatusForContact) {
        (original: $0, changed: $1)
    }
        .scan([ContactsSectionModel]()) { state, updates in
            // `state` is the last array handed to the table view.
            // `updates` contains the values from the combineLatest above.
            var contactModels = state.flatMap { $0.items.map { $0.model } }
            // get all the contactModels out of the state.
            if contactModels.isEmpty {
                contactModels = updates.original
            }
            // if there aren't any, then update with the values coming from `contacts`
            else {
                guard let index = contactModels
                        .firstIndex(where: { $0.id == updates.changed.id })
                else { return state }
                contactModels[index] = updates.changed
            }
            // otherwise find the index of the contact that changed.
            // and update the array with the changed contact.
            return [ContactsSectionModel(
                model: "",
                items: updates.original
                    .map { ContactCellModel(model: $0) }
            )]
            // rebuild the section model and return it.
        }

    contactsSectionModels
        .bind(to: tableView.rx.items(dataSource: dataSource))
        .disposed(by: disposeBag)
}

typealias ContactsSectionModel = AnimatableSectionModel<String, ContactCellModel>

struct ContactCellModel: Equatable, IdentifiableType {
    var identity: Int { model.id }
    let model: ContactModel
    let cellIdentifier = ContactTableViewCell.identifier
}

struct ContactModel: Equatable {
    let id: Int
    let name: String
    let avatar: String?
    let job: JobModel?
    let follow: Bool
}

struct JobModel: Equatable { }

class BaseTableViewCell: UITableViewCell {
    func setup(data: ContactModel) { }
}

class ContactTableViewCell: BaseTableViewCell {
    static let identifier = "Cell"
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM