0

I don't understand the correct way of using self inside Combine closure

class ViewModel {
    var requestPublisher = PassthroughSubject<Void, Never>()
    var nextPageAvailabe = true
    private var subscriptions = Set<AnyCancellable>()

    init() {
        setupSubscriptions()
    }

    setupSubscriptions() {
        requestPublisher
        .filter { _ in self.nextPageAvailabe }
        .sink(receiveValue: {
            print("Received request")  
        }).store(in: &subscriptions)
    }
}

requestPublisher.send() executed from parent class. Using .filter { _ in self.nextPageAvailabe } will lead to memory leak. So I need to use [weak self] or [unowned self] inside filter {}. And both solve the memory leak issue, but I don't understand the correct way. I have read several articles but couldn't find the answer. So what is the correct way of using self inside Combine closure?

Serhii Didanov
  • 2,200
  • 1
  • 16
  • 31
  • Does this answer your question? [What is the difference between a weak reference and an unowned reference?](https://stackoverflow.com/questions/24011575/what-is-the-difference-between-a-weak-reference-and-an-unowned-reference) – Andrew Oct 27 '22 at 12:50
  • @Andrew no, your link describe weak vs unowned inside plane swift not Combine. – Serhii Didanov Oct 27 '22 at 12:52
  • 2
    A closure is a closure it doesn’t matter whether it is used in combine or not. – Andrew Oct 27 '22 at 12:57
  • I have read this article several times, but still don't understand what to use in this case... – Serhii Didanov Oct 27 '22 at 13:01
  • 2
    It's to do with the life time of the object that is being captured by the closure. If you can guarantee that it will never be released before the closure is executed then you can use `unowned` if you don't know if it will be released or if you are unsure then use `weak`. – Andrew Oct 27 '22 at 13:04
  • In sort [weak self] alway works – SPatel Oct 27 '22 at 14:58

1 Answers1

0

weak is definitely the way to go : you will just have an optional self. When a weak variable is released, it just becomes nil.

unowned should be avoided as much as possible, as it is not runtime-safe : it is like weak, but the result is not optional. So if you try to use an unowned variable after it has been released, the app will simply crash.

    setupSubscriptions() {
        requestPublisher
        .filter { [weak self] _ in self?.nextPageAvailabe ?? false }
// I have put `?? false` because I suppose that if self is nil, then page is not available...
        .sink(receiveValue: {
            print("Received request")  
        }).store(in: &subscriptions)
    }
Pierre
  • 422
  • 2
  • 12
  • https://www.kodeco.com/books/combine-asynchronous-programming-with-swift - in the same case use unowned – Serhii Didanov Oct 27 '22 at 12:59
  • 1
    `unowned` *might* be OK in this case because when the object is destroyed its subscription is also destroyed which should prevent any of the closures in the observer chain from being called. Where you would get into trouble is if you shared the subscription with someone else. Even though it might work, using `weak` is the safer alternative, requires less critical thinking, doesn't introduce too much overhead, and so its generally a better habit to use `weak` instead of `unowned`. – Scott Thompson Oct 27 '22 at 13:19