Ok I just ran into something bizarre. I've got my app controller dependency injecting a view (header) into a view controller. That view controller presents another view controller modally and dependency injects it's own header for the presenting view controller to use. But when its presented the header from the first controller disappears.
The property is still set but it's been removed from the view hierarchy.
I've reproduced this issue in fresh singleview project:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
let button = UIButton(frame: CGRect(x: 0, y: 20, width: 100, height: 50))
button.setTitle("Click Me!", for: .normal)
button.addTarget(self, action: #selector(self.segue), for: .touchUpInside)
button.backgroundColor = .black
button.setTitleColor(.lightGray, for: .normal)
self.view.addSubview(button)
}
func segue() {
let view = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
view.backgroundColor = .lightGray
let firstVC = FirstViewController()
firstVC.sharedView = view
present(firstVC, animated: false)
}
}
class FirstViewController: UIViewController {
var sharedView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
self.view.addSubview(self.sharedView)
let button = UIButton(frame: CGRect(x: 0, y: 200, width: 100, height: 50))
button.setTitle("Click Me!", for: .normal)
button.addTarget(self, action: #selector(self.segue), for: .touchUpInside)
button.backgroundColor = .black
button.setTitleColor(.lightGray, for: .normal)
self.view.addSubview(button)
}
func segue() {
let secondVC = SecondViewController()
secondVC.sharedView = self.sharedView
present(secondVC, animated: true)
}
}
class SecondViewController: UIViewController {
var sharedView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
self.view.addSubview(self.sharedView)
let button = UIButton(frame: CGRect(x: 0, y: 200, width: 100, height: 50))
button.setTitle("Click Me!", for: .normal)
button.addTarget(self, action: #selector(self.segue), for: .touchUpInside)
button.backgroundColor = .black
button.setTitleColor(.lightGray, for: .normal)
self.view.addSubview(button)
}
func segue() {
self.dismiss(animated: true)
}
}
Can someone explain what's going on here? Why does the sharedView disappear from the FirstViewController?
At the doc of -addSubview(_:)
:
Views can have only one superview. If view already has a superview and that view is not the receiver, this method removes the previous superview before making the receiver its new superview.
That should explain your issue.
I'd suggest instead that you create a method that generate a headerView (a new one each time) according to your customization style.
If you really want to "copy" the view, you can check that answer. Since UIView
is not NSCopying Compliant, their trick is to "archive/encode" it since it's NSCoding compliant, copy that archive, and "unarchive/decode" the copy of it.