Skip to content

Observable Object got retained in ViewController-making closure after VC deinited. #250

@Lumisilk

Description

@Lumisilk

Description

Consider ViewModel is a @Observable class.
If I capture the viewModel in the ViewController-making content closure of .present (or any method else) like this:

@Observable
class ViewModel {
    var isPresented = false
}

class SheetViewController: UIViewController {

    @UIBindable var viewModel = ViewModel()
    
    override func viewDidLoad() {
        present(isPresented: $viewModel.isPresented) { [viewModel] in
            _ = viewModel
            return UIViewController()
        }
    }
}

After dismissing SheetViewController, the viewModel keeps alive. Even SheetViewController did actually been deinited.

I'm not sure this is a bug or expected behavior.

If I have to use ViewModel to create another UIViewController, how can I avoid this problem and get ViewModel be released?

Maybe something like this?

present(isPresented: $viewModel.isPresented) { [weak viewModel] in
    guard let viewModel else { return UIViewController() }
    return MyRealViewController(viewModel: viewModel)
}

Another similar situation

If I use observe and capture ViewModel in the closure, the ViewModel will be retained after dismissing only when I access the property of ViewModel. This behavior is expected because the closure was "registered" on the ViewModel itself.

// viewModel will be retained after dismissing, which is expected.
observe { [viewModel] in
    _ = viewModel.isThirdVCPresented
}

But in the example code of the main topic, I didn't even access any property of ViewModel.

Checklist

  • I have determined whether this bug is also reproducible in a vanilla SwiftUI project.
  • If possible, I've reproduced the issue using the main branch of this package.
  • This issue hasn't been addressed in an existing GitHub issue or discussion.

Expected behavior

ViewModel should be released.

Actual behavior

ViewModel got retained.

Steps to reproduce

I've uploaded a tiny project to reproduce this problem.
https://github.com/Lumisilk/SwiftNavigationBugExample

SwiftUI Navigation version information

2.2.2

Destination operating system

iOS 17, 18

Xcode version information

Xcode 16.1

Swift Compiler version information

swift-driver version: 1.115 Apple Swift version 6.0.2 (swiftlang-6.0.2.1.2 clang-1600.0.26.4)
Target: arm64-apple-macosx15.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions