0

From the documentation

An AnyCancellable instance automatically calls cancel() when deinitialized.

Yet in the following code

    var cancellable: AnyCancellable?

    let subject: PassthroughSubject<Int, Never>? = PassthroughSubject<Int, Never>()

    cancellable = subject?.sink(receiveValue: {
        print("-> sending to cancellable \($0)")
    })

    print("send 1")
    subject?.send(1)


    // documentation states "An AnyCancellable instance automatically calls cancel() when deinitialized."
    print("cancellable nil'd")
    cancellable = nil

    print("send 2")
    subject?.send(2)

    print("send 3")
    subject?.send(3)

    DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
        print("done")
    }

/*
send 1
-> sending to cancellable 1
cancellable nil'd
send 2
-> sending to cancellable 2
send 3
-> sending to cancellable 3
done
*/

Shows that nil'ing cancellable does not stop the subscriber from getting values.

While using a Set and removing all or nil'ing the set will stop the subscriptions. I even tried throwing everything into an autoreleasepool and it didn't do anything. Is the AnyCancellable in the code not getting deinitialized? Is something hanging on to it?

Test Playground

Yogurt
  • 2,913
  • 2
  • 32
  • 63

1 Answers1

3

You are testing this in a Playground. The Swift Playgrounds are notorious for hanging on to objects with an extra reference so that you can interact with them in the Playground. This makes the Playground a poor choice for testing the allocation and freeing of objects.

Try this in a real app and you should find that it works as advertised.


Note: I have found that it will sometimes work out in a Playground if you put all of your code into a function (such as test()) and then call the function. That prevents variables at top level from being defined and hanging on to object references.

vacawama
  • 150,663
  • 30
  • 266
  • 294