在 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
我正在尝试实现由后端发送的 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
.