I'm trying some patterns and at some point I realised my passthrough subject doesn't send anything when self is weak. Here what i did :
import Foundation
import Combine
class ViewModel {
var publisher = PassthroughSubject<[WebData], Never>()
let apis : [ApiProtocol]
init(apis: [ApiProtocol]){
self.apis = apis
getData()
}
func getData(){
guard !apis.isEmpty else { return }
apis.forEach {api in
api.getApiData { [weak self] webData in
self?.publisher.send(webData)
}
}
}
}
Since I declare [weak self] and write
self?.publisher.send(webData)
I don't receive any data from my sink closure in the view controller. But if I delete [weak self] and call use send method with a strong self :
func getData(){
guard !apis.isEmpty else { return }
apis.forEach {api in
api.getApiData { webData in
self.publisher.send(webData)
}
}
}
It sends data and view controller receives it perfectly. But now, didn't it cause a retain cycle? Why it doesn't send the data when self declared as weak? What am I missing here?
Edit : Here how I use sink closure:
class DataVC: UIViewController {
weak var viewModel : ViewModel?
var models = [WebData]()
var cancellable = [AnyCancellable]()
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
downloadData()
tableView.delegate = self
tableView.dataSource = self
}
func downloadData() {
guard let model = viewModel else { return }
model.publisher
.receive(on: DispatchQueue.main)
.sink { _ in
} receiveValue: { [weak self] value in
self?.models.append(contentsOf: value)
DispatchQueue.main.async {
self?.tableView.reloadData()
}
}.store(in: &cancellable)
}
}
DataVC table view protovol confirmances are in the extension. They work just fine, so I didn't add them here.
Edit2: Now I change declaration of viewModel in view controller from :
weak var viewModel : ViewModel?
to not weak one :
var viewModel : ViewModel!
... and it works with weak referenced publisher at the beginning. Ok, this solved my problem. But, then, why when viewModel is weak, even I (guard-let) unwrap it before use, it doesn't work?
why when viewModel is weak, even I (guard-let) unwrap it before use, it doesn't work?
It's because weak is weak!
weak var viewModel : ViewModel?
That means "Don't retain viewModel". Nothing else retains your ViewModel object either, so it just vanishes instantly before you can use it. By the time you say
guard let model = viewModel
viewModel
is gone and has become nil, and we just return.