简体   繁体   中英

Swift workaround for protocols comparison

I know comparing protocols doesn't make any sense but my situation is dictated by choices and decisions taken before me. A table view's data source is an array of RowViewModel.

protocol RowViewModel {}

there's nothing in there (yet) to make it even conform to Equatable. Then my table has different cells, all of which implement that protocol:

func getCells() -> [RowViewModel] {
    var rows = [RowViewModel]()
    rows.append(Cell1ViewModel())
    rows.append(Cell2ViewModel())
    rows.append(Cell3ViewModel())

    return rows
}

Cell's view model:

class Cell1ViewModel: RowViewModel {
    var cellTitle: String
    ...
}

This structure is convenient but it now shoots me in the back because I now need to calculate delta to send specific tableView indexes to insert / delete rows. To calculate delta I need RowViewModel to conform to Equatable, which is possible but seems like a workaround that defies the initial point of using this approach. I'd like to do something like this:

let oldList = rows
let newList = getCells()

let deltaAdded = newList.filter { !oldList.contains($0) }.compactMap { newList.firstIndex(of: $0) }
let deltaRemoved = oldList.filter { !newList.contains($0) }.compactMap { oldList.firstIndex(of: $0) }

What is the best practice here? Is there a way to write a comparison function for concrete types conforming to the RowViewModel?

As I told in comment you would have something like:

class CellViewModel1: Equatable {

    // classes need explicit equatable conformance.
    static func == (lhs: CellViewModel1, rhs: CellViewModel1) -> Bool {
        // your implementation
        return true
    }

}

enum RowViewModel: Equatable { 
    
    // enum automatically is Equatable as long as all cases have Equatable associated types
    case cell1(CellViewModel1)

}

func test() {
    let oldList = [RowViewModel]()
    let newList = [RowViewModel]()

    let deltaAdded = newList.filter { !oldList.contains($0) }.compactMap { newList.firstIndex(of: $0) }
    let deltaRemoved = oldList.filter { !newList.contains($0) }.compactMap { oldList.firstIndex(of: $0) }
}

Notice that both enum and ViewModels must conform to Equatable . Still not 100% sure if this fits your necessities.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM