/* Here is some sample code for a quick test of adding 48 labels (8 to each of 6 stack views). The button at the top toggles between adding / removing the labels, so it can be run multiple times. On an iPad Air (`ME991LL/A`), I get 0.03 seconds or less. */ class ViewController: UIViewController { let theBtn: UIButton = { let v = UIButton() v.translatesAutoresizingMaskIntoConstraints = false v.setTitle("Add Views", for: .normal) v.setContentHuggingPriority(.required, for: .vertical) v.backgroundColor = .red return v }() let promptLabel: UILabel = { let v = UILabel() v.translatesAutoresizingMaskIntoConstraints = false v.textAlignment = .center v.text = "Tap button to:" return v }() let statLabel: UILabel = { let v = UILabel() v.translatesAutoresizingMaskIntoConstraints = false v.backgroundColor = .cyan v.textAlignment = .center v.text = "" return v }() let topStackView: UIStackView = { let v = UIStackView() v.axis = .vertical v.distribution = .fillEqually v.spacing = 4 v.translatesAutoresizingMaskIntoConstraints = false return v }() let hStackView: UIStackView = { let v = UIStackView() v.axis = .horizontal v.distribution = .fillEqually v.spacing = 8 v.translatesAutoresizingMaskIntoConstraints = false return v }() var stackViews: [UIStackView] = [UIStackView]() var jCounter = 1 override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white for _ in 1...6 { let v = UIStackView() v.axis = .vertical v.distribution = .fillEqually v.spacing = 8 v.translatesAutoresizingMaskIntoConstraints = false stackViews.append(v) } topStackView.addArrangedSubview(promptLabel) topStackView.addArrangedSubview(theBtn) topStackView.addArrangedSubview(statLabel) view.addSubview(topStackView) view.addSubview(hStackView) let g = view.safeAreaLayoutGuide NSLayoutConstraint.activate([ topStackView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0), topStackView.centerXAnchor.constraint(equalTo: g.centerXAnchor, constant: 0.0), topStackView.widthAnchor.constraint(equalToConstant: 300.0), hStackView.topAnchor.constraint(equalTo: topStackView.bottomAnchor, constant: 20.0), hStackView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -8.0), hStackView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0), hStackView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0), ]) stackViews.forEach { hStackView.addArrangedSubview($0) } theBtn.addTarget(self, action: #selector(addViews(_:)), for: .touchUpInside) } func doAddViews() -> Void { let start = CFAbsoluteTimeGetCurrent() stackViews.forEach { sv in for _ in 1...8 { let v = UILabel() v.font = UIFont.systemFont(ofSize: 10.0, weight: .medium) v.backgroundColor = .yellow v.textAlignment = .center v.text = "\(jCounter)" sv.addArrangedSubview(v) jCounter += 1 } } let end = CFAbsoluteTimeGetCurrent() - start statLabel.text = "Elapsed Time: \(end)" } @objc func addViews(_ sender: Any?) -> Void { if stackViews.first?.arrangedSubviews.count == 0 { doAddViews() theBtn.setTitle("Clear Views", for: .normal) } else { stackViews.forEach { sv in sv.arrangedSubviews.forEach { $0.removeFromSuperview() } } statLabel.text = "" theBtn.setTitle("Add Views", for: .normal) } } }