Combine Migration?

Viewed 534

How to replace closure or delegation callback which get called when user tap on a button of a table view cell with Combine framework ?

problem - if Subscriber is added from the view controller and store returned AnyCancellable in a Set ; 1. storage of anyCancellable is getting heigh as cell return .2. many subscribers receive value when user tap on one button of a cell

I used built in subscriber Sink

In ViewController

 var myAnyCancellableSet: Set<AnyCancellable> = []

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "mycell")
        cell.doSomethingSubject.sink { 
print("user tap button on cell")
                            }.store(in: &myAnyCancellableSet)
        return cell
                    }

In tableview cell

import UIKit
import Combine

class MyTableViewCell: UITableViewCell {
   
    private lazy var myDoSomethingSubject = PassthroughSubject<Void, Never>()
    lazy var doSomethingSubject = myDoSomethingSubject.eraseToAnyPublisher()
    
   @IBAction func buttonTapped(_ sender: UIButton) {
        myDoSomethingSubject.send()
    }

}
1 Answers

Don't store all your tickets together. Store them by index path.

var ticketForIndexPath: [IndexPath: AnyCancellable] = [:]

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "mycell") as! MyCell
    ticketForIndexPath[indexPath] = cell.doSomethingSubject.sink {
        print("user tap button on cell")
    }
    return cell
}

func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    ticketForIndexPath[indexPath] = nil
}
Related