 	}
 }
 
+class Label {
+	let view: UILabel
+	var ownerHash: RegionHash
+	
+	init() {
+		view = UILabel()
+		view.isHidden = true
+		view.frame = CGRect(x: 0.0, y: 0.0, width: 200.0, height: 30.0)
+		view.preferredMaxLayoutWidth = 200.0
+		view.lineBreakMode = .byWordWrapping
+		view.numberOfLines = 2
+		view.adjustsFontSizeToFitWidth = true
+		
+		ownerHash = 0
+	}
+}
+
 class LabelView: UIView {
 	static let s_maxLabels = 20
-	var poiPrimitives: [Int: LabelMarker] = [:]
-	var poiLabels: [UILabel] = []
+	var poiPrimitives: [Int : LabelMarker] = [:]
+	var poiLabels: [Label] = []
 	
 	override func awakeFromNib() {
 		for _ in 0 ..< LabelView.s_maxLabels {
-			let newLabel = UILabel()
-			newLabel.tag = 0
-			newLabel.isHidden = true
-			newLabel.frame = CGRect(x: 0.0, y: 0.0, width: 200.0, height: 30.0)
-			newLabel.preferredMaxLayoutWidth = 200.0
-			newLabel.lineBreakMode = .byWordWrapping
-			newLabel.numberOfLines = 2
-			newLabel.adjustsFontSizeToFitWidth = true
-			
+			let newLabel = Label()
 			poiLabels.append(newLabel)
-			addSubview(newLabel)
+			addSubview(newLabel.view)
 		}
 	}
 	

			 .foregroundColor: textColor,
			 .strokeWidth: strokeWidth]
		
		label.textAlignment = alignment
		label.attributedText = NSAttributedString(string: marker.name, attributes: strokeAttribs)
	}
	
	func unbindLabel(_ label: UILabel) {
		label.tag = 0
		label.isHidden = true
	}
}

		let markersToShow = prioritizedMarkers.prefix(LabelView.s_maxLabels)
		let hashesToShow = markersToShow.map { $0.ownerHash }
		
		// First free up any labels that no longer have active markers
		_ = poiLabels
			.filter({ $0.ownerHash != 0 && !hashesToShow.contains($0.ownerHash) })
			.map(unbindLabel)
		
		// Bind new markers into free labels
		for marker in markersToShow {
			guard poiLabels.first(where: { $0.ownerHash == marker.ownerHash }) == nil else {
				continue
			}
			guard let freeLabel = poiLabels.first(where: { $0.ownerHash == 0 }) else {
				print("Marker \(marker.ownerHash) could not be bound to a free label")
				continue
			}
