Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

UIInputView not being deallocated

I am experiencing memory leaks in my iOS app that seem to be related to an issue between UIInputView and _UIInputViewContent. After using the memory graph, I'm seeing that instances of these objects aren't being deallocated properly.

The UIInputViewController whichs holds the inputView is being deallocated properly along with its subviews.I have tried to remove all of UIInputViewController's subviews and their functions but the uiInputView is not being deallocated.

The current setup of my app is a collectionView with multiple cells,each possessing a textfield with holds a UIInputViewController.When i scroll up or down,the views are being reused as expected and the number of UIInputViewController stays consistent with the number of textfields.However the number of inputView keeps increasing referencing solely _UIInputViewContent.

class KeyboardViewController: UIInputViewController {
    
    // Callbacks
    var key1: ((String) -> Void)?
    var key2: (() -> Void)?
    var key3: (() -> Void)?
    var key4: (() -> Void)?
    
    private lazy var buttonTitles = [
        ["1", "2", "3"],
        ["4", "5", "6"],
        ["7", "8", "9"]
    ]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupKeyboard()
    }
    
    lazy var mainStackView: UIStackView = {
        let mainStackView = UIStackView()
        mainStackView.axis = .vertical
        mainStackView.distribution = .fillEqually
        mainStackView.spacing = 16
        mainStackView.translatesAutoresizingMaskIntoConstraints = false
        return mainStackView
    }()
    
    
    private func setupKeyboard() {
        let keyboardView = UIView(frame:CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 279.0))
        
        keyboardView.addSubview(mainStackView)
        
        NSLayoutConstraint.activate([
            mainStackView.topAnchor.constraint(equalTo: keyboardView.topAnchor, constant: 16),
            mainStackView.leadingAnchor.constraint(equalTo: keyboardView.leadingAnchor, constant: 0),
            mainStackView.trailingAnchor.constraint(equalTo: keyboardView.trailingAnchor, constant: -24),
            mainStackView.bottomAnchor.constraint(equalTo: keyboardView.bottomAnchor, constant: -35)
        ])
        
        // Create rows
        for (_, _) in buttonTitles.enumerated() {
            let rowStackView = UIStackView()
            
            rowStackView.axis = .horizontal
            rowStackView.distribution = .fillEqually
            rowStackView.spacing = 1
            
//             Create buttons for each row
            for title in rowTitles {
                let button = createButton(title: title)
                rowStackView.addArrangedSubview(button)
            }
            
            mainStackView.addArrangedSubview(rowStackView)
        }
        self.view = keyboardView
    }
    
    private func createButton(title: String) -> UIButton {
        switch title {
            ///returns a uibutton based on title
        }
    }
    
    // MARK: - Button Actions
    @objc private func numberTapped(_ sender: UIButton) {
        if let number = sender.title(for: .normal) {
            key1?(number)
        }
    }
    
    @objc private func key2Called() {
        key2?()
    }

    @objc private func key3Called() {
        key3?()
    }

    @objc private func key4Called() {
        key4?()
    }
    
    deinit {
        // Clear any strong references
        key1 = nil
        key2 = nil
        key3 = nil
        key4 = nil
        
        for subview in mainStackView.arrangedSubviews {
            if let stackView = subview as? UIStackView {
                for button in stackView.arrangedSubviews {
                    (button as? UIButton)?.removeTarget(self, action: nil, for: .allEvents)
                }
            }
        }
        mainStackView.removeFromSuperview()
    }
}

Environment

iOS 16.3 Xcode 18.3.1

Any insights would be greatly appreciated as this is causing noticeable memory growth in my app over time.

No need to make a duplicate post to correct a spelling mistake...

UIInputView not being deallocated
 
 
Q