 	
 	fileprivate var indentationLevel: Int {
 		return parent?.isViewable == true ? parent!.indentationLevel + 1 : parent?.indentationLevel ?? 0
+	}
+	
+	private var batchUpdatesCounter: Int = 0
+	private var isInBatch: Bool {
+		return batchUpdatesCounter > 0 || parent?.isInBatch ?? false
+	}
+	
+	func performBatchUpdates(_ updates: () -> Void) {
+		if !isInBatch {
+			let from = _children
+			let size = self.size
+			
+			batchUpdatesCounter += 1
+			updates()
+			batchUpdatesCounter -= 1
+			
+			let to = _children ?? []
+			if let from = from {
+				var set = Set(from)
+				for a in to {
+					if let b = set.remove(a) {
+						a.update(from: b)
+					}
+				}
+			}
+			
+			if from != nil, let treeController = treeController, let index = flatIndex {
+				let range = index..<(index + size)
+				let to = flattened
+				if range.count < TransitionItemsLimit && to.count < TransitionItemsLimit {
+					treeController.replaceNodes(at: range, with: to)
+				}
+				else {
+					UIView.performWithoutAnimation {
+						treeController.replaceNodes(at: range, with: to)
+					}
+				}
+			}
+		}
+		else {
+			batchUpdatesCounter += 1
+			updates()
+			batchUpdatesCounter -= 1
+		}
 	}
 }
 

					}
				}
				
				
				_children = to
				let range = index..<(index + size)
				let to = flattened
				if range.count < TransitionItemsLimit && to.count < TransitionItemsLimit {
					treeController.replaceNodes(at: range, with: to)
				}
				else {
					UIView.performWithoutAnimation {
						treeController.replaceNodes(at: range, with: to)
					}
				}
			}
			else {
				_children = to
			}
			for child in from ?? [] {
				child.parent = nil
			}

		super.init()
	}
	
	
	private var _children: [TreeNode]?
	public var children: [TreeNode] {
		get {
