Search code examples
rx-swift

How to replace a simple delegate protocol with RxSwift?


I'm looking for the optimal way to avoid defining

protocol SomeTableviewCellDelegate: class {
    func didSelectTopic(topic: RTopic)
}

and use RxSwift instead.

I already have defined

var didSelectTopic: Observable<RTopic> {
    return _didSelectTopic.asObservable()
}
private let _didSelectTopic = PublishSubject<RTopic>()

var didDeselectTopic: Observable<RTopic> {
     return _didDeselectTopic.asObservable()
}
private let _didDeselectTopic = PublishSubject<RTopic>()

I can't find the proper way to emit a topic (I am new to RxSwift).


Solution

  • You trying to pass information about selected items (Correct me if I wrong).

    Currently selected items

    We don't care about selection / unselection, we care only about items, that selected in each moment of time.

    This is probably most common use case, since your user (user of component) doesn't need to have local state.

    protocol TopicSelectionProvider {
        var selectedTopicsStream: Observable<Set<RTopic>> { get }
    }
    
    class MyTableDelegate: NSObject, UITableViewDelegate {
        private var selectedTopics = BehaviourRelay<Set<RTopic>>([])
        ...
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            var selected = selectedTopics.value
            selected.insert(topics[indexPath.row])
            selectedTopics.accept(selected)
        }
    
        func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
            var selected = selectedTopics.value
            selected.remove(topics[indexPath.row])
            selectedTopics.accept(selected)
        }
    }
    
    extension MyTableDelegate: TopicSelectionProvider {
        var selectedTopicsStream: Observable<Set<RTopic>> {
            return selectedTopics.asObservable()
        }
    }
    

    Selection / Unselection events

    We don't care about selected items, we only interested in events them self.

    This use case can be used, when you don't need items, but events (for api calls for example).

    enum TopicSelectionEvent {
        case select(RTopic)
        case deselect(RTopic)
    }
    
    protocol TopicSelectionProvider {
        var topicSelectionStream: Observable<TopicSelectionEvent> { get }
    }
    
    class MyTableDelegate: NSObject, UITableViewDelegate {
        private var topicSelection = PublishSubject<TopicSelectionEvent>()
        ...
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            topicSelection.onNext(.select(topics[indexPath.row]))
        }
    
        func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
            topicSelection.onNext(.deselect(topics[indexPath.row]))
        }
    }
    
    extension MyTableDelegate: TopicSelectionProvider {
        var topicSelectionStream: Observable<TopicSelectionEvent> {
            return topicSelection.asObservable()
        }
    }
    

    Both approach valid and have proc and cons. Choose one that suits you best.