I have a fairly simple code which, upon clicking a button, adds a randomly colored UIView
to a UIStackView
, and upon a different button click, removes a random UIView
from the UIStackView
.
Here's the code:
import UIKit
class ViewController: UIViewController, Storyboarded {
weak var coordinator: MainCoordinator?
@IBOutlet weak var stackView: UIStackView!
var tags: [Int] = []
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func buttonPressed(_ sender: UIButton) {
switch sender.tag {
case 10:
let view = UIView(frame: CGRect(x: 0, y: 0, width: stackView.frame.width, height: 20))
var number = Int.random(in: 0...10000)
while tags.contains(number) {
number = Int.random(in: 0...10000)
}
tags.append(number)
view.tag = number
view.backgroundColor = .random()
stackView.addArrangedSubview(view)
case 20:
if tags.count == 0 {
print("Empty")
return
}
let index = Int.random(in: 0...tags.count - 1)
let tag = tags[index]
tags.remove(at: index)
if let view = stackView.arrangedSubviews.first(where: { $0.tag == tag }) {
stackView.removeArrangedSubview(view)
}
default:
break
}
}
}
extension CGFloat {
static func random() -> CGFloat {
return CGFloat(arc4random()) / CGFloat(UInt32.max)
}
}
extension UIColor {
static func random() -> UIColor {
return UIColor(
red: .random(),
green: .random(),
blue: .random(),
alpha: 1.0
)
}
}
I'm not using removeFromSuperview
on purpose - since I would (later) want to reuse those removed UIViews
, and that is why I'm using removeArrangedSubview
.
The issue I'm facing is:
All UIViews
are removed as expected (visually of course, I know they're still in the memory) until I reach the last one - which, even though was removed, still appears and filling the entire UIStackView
.
What am I missing here?
You can understand removeArrangedSubview
is for removing constraints that were assigned to the subview. Subviews are still in memory and also still inside the parent view.
To achieve your purpose, you can define an array as your view controller's property, to hold those subviews, then use removeFromSuperview
.
Or use .isHidden
property on any subview you need to keep it in memory rather than removing its contraints. You will see the stackview do magical things to all of its subviews.
let subview = UIView()
stackView.addArrangedSubview(subview)
func didTapButton(sender: UIButton) {
subview.isHidden.toggle()
}
Last, addArrangedSubview
will do two things: add the view to superview if it's not in superview's hierachy and add contraints for it.