UIInputView is not deallocated from memory

When a subclass of UIInputView is created programmatically, a memory leak occurs. This issue can be easily reproduced even with a very simple sample project, so I’m submitting this report along with a minimal reproducible example.

When a custom view subclassing UIInputView is instantiated in code, _InputViewContent retains the custom view, and the custom view also holds a reference back to _InputViewContent, creating a strong reference cycle that prevents deallocation.

The issue consistently occurs and has been confirmed on Xcode 16.4, 26.0, and 26.1.

As a workaround, initializing the view via Storyboard allows it to be properly deallocated from memory. (Please refer to the CustomInputView in the attached sample code.)

import UIKit

final class LeakInputView: UIInputView {
    deinit {
        print("LeakInputView deinit") // not called
    }
}

final class CustomInputView: UIInputView {
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override init(frame: CGRect, inputViewStyle: UIInputView.Style) {
        super.init(frame: frame, inputViewStyle: inputViewStyle)
    }

    deinit {
        print("CustomInputView deinit") // called
    }
}

extension CustomInputView {
    static func loadFromNib() -> CustomInputView {
        let nib = UINib(nibName: "CustomInputView", bundle: nil)
        guard let view = nib.instantiate(withOwner: nil, options: nil).first as? CustomInputView else {
            fatalError("Failed to load CustomInputView from nib.")
        }
        return view
    }
}

final class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .red

        LeakInputView()
        LeakInputView()
        LeakInputView()
        CustomInputView.loadFromNib()
        CustomInputView.loadFromNib()
        CustomInputView.loadFromNib()

        DispatchQueue.main.async {
            print("Next runloop tick")
        }
    }
}
UIInputView is not deallocated from memory
 
 
Q