Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
121 views
in Technique[技术] by (71.8m points)

ios - Keeping strong references with dynamic subviews in Swift

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.

So for example the sever sends:

  • type: paragraph
  • type: textfield

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

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

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.

The TextField:

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)
    }
}
question from:https://stackoverflow.com/questions/65882928/keeping-strong-references-with-dynamic-subviews-in-swift

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...