Skip to content

Instantly share code, notes, and snippets.

@hlung
Last active October 25, 2020 10:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hlung/b9373f9fec70257de79fb3c741b2e776 to your computer and use it in GitHub Desktop.
Save hlung/b9373f9fec70257de79fb3c741b2e776 to your computer and use it in GitHub Desktop.
Find the least common ancestor of 2 views.
import Foundation
import UIKit
// From an example view hierarchy...
// 1 -> 2 -> 3 -> 4 -> 5
// |
// ---> 6
// Find the least common ancestor of 2 views.
// Input
let view1 = UIView()
let view2 = UIView()
let view3 = UIView()
let view4 = UIView()
let view5 = UIView()
let view6 = UIView()
view1.addSubview(view2)
view2.addSubview(view3)
view3.addSubview(view4)
view4.addSubview(view5)
view2.addSubview(view6)
// Output
commonSuperview(view5, view6) == view2
// Helper functions
extension UIView {
var lineage: [UIView] {
var candidateView: UIView? = self
var output: [UIView] = []
while let c = candidateView {
output.append(c)
candidateView = c.superview
}
return output
}
}
//view5.lineage == [view5, view4, view3, view2, view1]
//view6.lineage == [view6, view2, view1]
func commonSuperview(_ v1: UIView, _ v2: UIView) -> UIView? {
// First we create an array of lineage of both views.
// - We use reversed() because ending parts (heighest ancestor) of both arrays are likely to be identical.
// So it is easier to compare them.
// - We use makeIterator() to allow moving element by element easily.
var lineage1 = v1.lineage.reversed().makeIterator()
var lineage2 = v2.lineage.reversed().makeIterator()
// Then find the last matching views between both arrays.
var lastMatch: UIView? = nil
while let c1 = lineage1.next(), let c2 = lineage2.next(), c1 == c2 {
lastMatch = c1
}
return lastMatch
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment