Skip to content

Commit

Permalink
Support nested batches (without combining their constraints)
Browse files Browse the repository at this point in the history
  • Loading branch information
sanekgusev committed Dec 7, 2017
1 parent dedc3b8 commit 6330843
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 11 deletions.
45 changes: 45 additions & 0 deletions AnchorageTests/AnchorageTests.swift
Expand Up @@ -588,6 +588,51 @@ class AnchorageTests: XCTestCase {
XCTAssertEqual(height.firstAttribute, .height)
XCTAssertEqual(height.secondAttribute, .height)
}

func testNestedBatchConstraints() {
var nestedConstraints: [NSLayoutConstraint] = []
let constraints = Anchorage.batch {
view1.widthAnchor == view2.widthAnchor
nestedConstraints = Anchorage.batch(active: false) {
view1.heightAnchor == view2.heightAnchor / 2 ~ .low
}
view1.leadingAnchor == view2.leadingAnchor
}

let width = constraints[0]
let leading = constraints[1]
let height = nestedConstraints[0]

assertIdentical(width.firstItem, view1)
assertIdentical(width.secondItem, view2)
XCTAssertEqual(width.constant, 0, accuracy: cgEpsilon)
XCTAssertEqual(width.multiplier, 1, accuracy: cgEpsilon)
XCTAssertEqual(width.priority.rawValue, TestPriorityRequired.rawValue, accuracy: fEpsilon)
XCTAssertTrue(width.isActive)
XCTAssertEqual(width.relation, .equal)
XCTAssertEqual(width.firstAttribute, .width)
XCTAssertEqual(width.secondAttribute, .width)

assertIdentical(height.firstItem, view1)
assertIdentical(height.secondItem, view2)
XCTAssertEqual(height.constant, 0, accuracy: cgEpsilon)
XCTAssertEqual(height.multiplier, 0.5, accuracy: cgEpsilon)
XCTAssertEqual(height.priority.rawValue, TestPriorityLow.rawValue, accuracy: fEpsilon)
XCTAssertFalse(height.isActive)
XCTAssertEqual(height.relation, .equal)
XCTAssertEqual(height.firstAttribute, .height)
XCTAssertEqual(height.secondAttribute, .height)

assertIdentical(leading.firstItem, view1)
assertIdentical(leading.secondItem, view2)
XCTAssertEqual(leading.constant, 0, accuracy: cgEpsilon)
XCTAssertEqual(leading.multiplier, 1, accuracy: cgEpsilon)
XCTAssertEqual(leading.priority.rawValue, TestPriorityRequired.rawValue, accuracy: fEpsilon)
XCTAssertTrue(leading.isActive)
XCTAssertEqual(leading.relation, .equal)
XCTAssertEqual(leading.firstAttribute, .leading)
XCTAssertEqual(leading.secondAttribute, .leading)
}

}

Expand Down
10 changes: 3 additions & 7 deletions Source/Anchorage.swift
Expand Up @@ -397,7 +397,6 @@ infix operator ~: PriorityPrecedence

/// Any Anchorage constraints created inside the passed closure are returned in the array.
///
/// - Precondition: Can't be called inside or simultaneously with another batch. Batches cannot be nested.
/// - Parameter closure: A closure that runs some Anchorage expressions.
/// - Returns: An array of new, active `NSLayoutConstraint`s.
@discardableResult public func batch(_ closure: () -> Void) -> [NSLayoutConstraint] {
Expand All @@ -406,19 +405,16 @@ infix operator ~: PriorityPrecedence

/// Any Anchorage constraints created inside the passed closure are returned in the array.
///
/// - Precondition: Can't be called inside or simultaneously with another batch. Batches cannot be nested.
/// - Parameter active: Whether the created constraints should be active when they are returned.
/// - Parameter closure: A closure that runs some Anchorage expressions.
/// - Returns: An array of new `NSLayoutConstraint`s.
public func batch(active: Bool, closure: () -> Void) -> [NSLayoutConstraint] {
precondition(currentBatch == nil)
let batch = ConstraintBatch()
batches.append(batch)
defer {
currentBatch = nil
batches.removeLast()
}

let batch = ConstraintBatch()
currentBatch = batch

closure()

if active {
Expand Down
8 changes: 4 additions & 4 deletions Source/Internal.swift
Expand Up @@ -312,7 +312,7 @@ internal struct ConstraintBuilder {

// MARK: - Batching

internal var currentBatch: ConstraintBatch?
internal var batches: [ConstraintBatch] = []

internal class ConstraintBatch {

Expand All @@ -333,7 +333,7 @@ internal class ConstraintBatch {
///
/// - Parameter closure: The work to perform inside of a batch
internal func performInBatch(closure: () -> Void) {
if currentBatch == nil {
if batches.isEmpty {
batch(closure)
}
else {
Expand All @@ -351,8 +351,8 @@ internal func finalize(constraint: NSLayoutConstraint, withPriority priority: Pr

constraint.priority = priority.value

if let currentBatch = currentBatch {
currentBatch.add(constraint: constraint)
if let lastBatch = batches.last {
lastBatch.add(constraint: constraint)
}
else {
constraint.isActive = true
Expand Down

0 comments on commit 6330843

Please sign in to comment.