在 Swift 中使用动态子视图保持强引用 [英] Keeping strong references with dynamic subviews in Swift

查看:29
本文介绍了在 Swift 中使用动态子视图保持强引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to implement a dynamic view composed UI elements sent by the backend, meaning it is not known beforehand how many and which UI elements will be displayed, the server sends JSON containing the types of fields that need to be rendered.

例如服务器发送:

  • 类型:段落
  • 类型:文本字段

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

Then I instantiate a class I have for each of those elements and add their views as subviews to my main dynamic view:

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 分配给特定变量时,它确实有效:

The problem I am getting with the "textfield" element, is that the textfield doesn't seem to be editable, tapping on it does nothing. However, when I change the code to assign the initializedClass.view to a specific variable, it does work:

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!)
                }
            }
        })
    }
}

然后第二个实现工作(选择器打开),这是我从 UIPickerView 委托未在子视图中调用.

This second implementation works then (the picker does open), which I got from UIPickerView delegate not called in a subview.

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

My question is why this is happening and how I can make this work without having to declare static variables for each element, but rather work with an array or some collection that keep references to the elements.

文本字段:

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

From your code it looks like getClass() will return a subclass of UIViewController (I can see this because you are calling addChild). You also have to call initializedClass.didMove(toParent: self) sometimes after addChild otherwise the embedding of the VC is not completed and could cause issues. I am not entirely sure this is the cause of your problem but I suggest to try it. Also when implementing a container VC you need to take care of AutoLayout for the children's view, where are you managing the constraints? If you don't add any constraint the view of the VC you are adding as child will have the same size of the main UIWindow. You actually could also get rid of var subViews: [UIView] = [] and just rely on children array from UIViewController. It will contain all the VCs you add when calling addChild.

这篇关于在 Swift 中使用动态子视图保持强引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆