Can I use weak to check for retain cycles?

I've got a class that initializes some blocks and such, and want to ensure I don't have any retain cycles. I'm attempting to write a unit test to verify some simple cases, like this:

func testThat_MyClass_WillRelease() {
    weak var myClass = MyClass()

    XCTAssertNil(myClass)
}

For many cases this seems to work, but I've encountered a class where this doesn't work. When I add some prints around the deinit calls like this:

class MyClass {
    deinit {
        print("MyClass: deinit")
    }
}

func testThat_MyClass_WillRelease() {
   weak var myClass = MyClass()

   print("Checking for nil")
   XCTAssertNil(myClass)
}

What I'm seeing in the output is not in the order I expect:

Checking for nil
MyClass: deinit

So this explains why my test assertion is failing. But I don't understand why this is happening.

I've tried doing a few things to force an out-of-scope call to deinit, but nothing seems to work...

  1. Wrapping in do {} or a function call:
func testThat_MyClass_WillRelease() {
    weak var myClass: MyClass?

    do {
        myClass = MyClass()
    }

    XCTAssertNil(myClass)
}

  1. Wrapping in autoreleasepool {}
func testThat_MyClass_WillRelease() {
    weak var myClass: MyClass?

    autoreleasepool {
        myClass = MyClass()
    }

    XCTAssertNil(myClass)
}

I've tried other more complicated things as well. What am I missing? Is there a better way to write a unit test like this?

Thanks

What I'm seeing in the output is not in the order I expect:

I tested this (with Xcode 15.4) and it didn’t reproduce for me. However, I do have a suggestion for how to investigate: Set a breakpoint on the print(…) call in your deinitialiser and look at the backtrace to see where that last ref is being released.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

1 Like

What if instead of weak reference, use checking references count from Foundation of ˋisKnownUniquelyReferenced` from Swift stdlib? That seems to be more obvious (from reader perspective) and determined way to test, since in test case there should be only one reference to the instance.

1 Like

Is that an NSObject subclass?