在 Swift 中使用动态子视图保持强引用

Keeping strong references with dynamic subviews in Swift

我正在尝试实现由后端发送的 UI 元素组成的动态视图,这意味着事先不知道将显示多少和哪些 UI 元素,服务器发送 JSON包含需要渲染的字段类型

例如服务器发送:

然后我为每个元素实例化一个 class 并将它们的视图作为子视图 添加到我的主动态视图中::

class DynamicViewController: UIViewController {
    // array of subviews, textfield is one element in this array (-> textfield not editable)
    var subViews: [UIView] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        
        getFields(completion: { result in
            for (index, element) in result!.form.enumerated() {
                let initializedClass = element.getClass()
                self.subViews.append(initializedClass.view)
                self.addChild(initializedClass)
                self.view.addSubview(self.subViews[index])
                initializedClass.didMove(toParent: self)
            }
        })
    }
}

问题 我遇到的“文本字段”元素是文本字段似乎不可编辑,点击它没有任何作用。 但是,当我更改代码以将 initializedClass.view 分配给特定变量时,它确实有效:

class DynamicViewController: UIViewController {
    // variable specifically for the textfield's view (-> textfield is editable)
    var textfieldView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        getFields(completion: { result in
            for (index, element) in result!.form.enumerated() {
                if (index == 0) {
                    let initializedClass = element.getClass()
                    let initializedView = initializedClass.view
                    self.textfieldView = initializedClass.view
                    self.addChild(initializedClass)
                    self.view.addSubview(initializedView!)
                }
            }
        })
    }
}

我从 .

获得的第二个实现随后工作(选择器确实打开)

我的问题是为什么会发生这种情况,以及我如何在不必为每个元素声明静态变量的情况下使它工作,而是使用一个数组或一些集合来保持对元素的引用。

文本字段:

class CustomTextField: UIViewController {
    private let labelElement = UILabel(frame: CGRect(x: 20, y: 150, width: 350, height: 20))
    private let textfieldElement = UITextField(frame: CGRect(x: 20, y: 200, width: 350, height: 40))
    
    init(label: String) {
        self.labelElement.text = label
        textfieldElement.borderStyle = UITextField.BorderStyle.roundedRect
        
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(labelElement)
        view.addSubview(textfieldElement)
    }
}

从您的代码看来 getClass() 将 return 成为 UIViewController 的子类(我可以看到这一点,因为您正在调用 addChild)。您还必须有时在 addChild 之后调用 initializedClass.didMove(toParent: self) ,否则 VC 的嵌入未完成并可能导致问题。我不完全确定这是你问题的原因,但我建议尝试一下。此外,在实现容器 VC 时,您需要为子视图处理 AutoLayout,您在哪里管理约束?如果您不添加任何约束,则作为子项添加的 VC 的视图将与主视图 UIWindow 具有相同的大小。 实际上,您也可以摆脱 var subViews: [UIView] = [],而只依赖 UIViewController 中的 children 数组。它将包含您在调用 addChild.

时添加的所有 VC