Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI memory leak when using UIViewControllerRepresentable

Tags:

swiftui

UPDATE: As of beta4, problem still present.

I have created a very simple example of how a UIViewController represented by UIViewControllerRepresentable is never deallocated.

import SwiftUI

struct ContentView : View {
    @State private var showRepView = true

    var body: some View {
        VStack {
            Text("Square").font(.largeTitle).tapAction {
                self.showRepView.toggle()
            }

            if showRepView {
                SomeRepView().frame(width: 100, height: 100)
            }
        }

    }
}

The representation implementation follows:

import SwiftUI

struct SomeRepView: View {
    var body: some View {
        RepViewController()
    }
}

struct RepViewController: UIViewControllerRepresentable
{
    func makeUIViewController(context: Context) -> SomeCustomeUIViewController {
        let vc =  SomeCustomeUIViewController()
        print("INIT \(vc)")
        return vc
    }

    func updateUIViewController(_ uiViewController: SomeCustomeUIViewController, context: Context) {
    }

    static func dismantleUIViewController(_ uiViewController: SomeCustomeUIViewController, coordinator: Self.Coordinator) {
        print("DISMANTLE")
    }

}

class SomeCustomeUIViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.green
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        print("viewWillDissapear \(self)")
    }

    deinit {
        print("DEINIT \(self)")
    }

}

By tapping on the "Square" button, SomeRepView is added and removed alternatively. However, the related UIViewController is never released. That can be seen by the logged messages and I also confirmed with Instruments.

Note that SomeRepView is released properly. It is only the corresponding view controller what remains allocated.

Also note that the UIViewController.viewWillDissappear is called and also the UIViewControllerRepresentable.dismantleUIViewController

This is a typical output of pressing the Square button repeatedly.

INIT <SomeCustomeUIViewController: 0x100b1af70>
DISMANTLE
viewWillDissapear <SomeCustomeUIViewController: 0x100b1af70>
INIT <SomeCustomeUIViewController: 0x100a0a8c0>
DISMANTLE
viewWillDissapear <SomeCustomeUIViewController: 0x100a0a8c0>
INIT <SomeCustomeUIViewController: 0x100b23690>
DISMANTLE
viewWillDissapear <SomeCustomeUIViewController: 0x100b23690>

As show, DEINIT is never printed.

My question is... is it a bug? Or am I doing something wrong?

Running with iOS13, beta 4.

I tried triggering Simulate Memory Warning. No effect. The controllers persist. Instruments is my witness ;-)

like image 489
kontiki Avatar asked Jun 21 '19 07:06

kontiki


1 Answers

In Xcode 11, beta 5, bug was patched.

like image 149
kontiki Avatar answered Nov 27 '22 22:11

kontiki