Fix Memory Leaks

This commit is contained in:
Robert Payne 2016-11-24 00:03:41 +13:00
parent ddf15594fd
commit eb107818ac
5 changed files with 55 additions and 28 deletions

View File

@ -27,7 +27,8 @@
import AppKit import AppKit
#endif #endif
public class Constraint { @objc(SnapKitConstraint)
public final class Constraint : NSObject {
internal let sourceLocation: (String, UInt) internal let sourceLocation: (String, UInt)
internal let label: String? internal let label: String?
@ -67,6 +68,7 @@ public class Constraint {
self.constant = constant self.constant = constant
self.priority = priority self.priority = priority
self.layoutConstraints = [] self.layoutConstraints = []
super.init()
// get attributes // get attributes
let layoutFromAttributes = self.from.attributes.layoutAttributes let layoutFromAttributes = self.from.attributes.layoutAttributes
@ -260,7 +262,7 @@ public class Constraint {
} }
for layoutConstraint in layoutConstraints { for layoutConstraint in layoutConstraints {
let existingLayoutConstraint = existingLayoutConstraints.first { $0.canUpdate(constraint: layoutConstraint) } let existingLayoutConstraint = existingLayoutConstraints.first { $0 == layoutConstraint }
guard let updateLayoutConstraint = existingLayoutConstraint else { guard let updateLayoutConstraint = existingLayoutConstraint else {
fatalError("Updated constraint could not find existing matching constraint to update: \(layoutConstraint)") fatalError("Updated constraint could not find existing matching constraint to update: \(layoutConstraint)")
} }

View File

@ -45,7 +45,7 @@ public class ConstraintDescription {
let sourceLocation = self.sourceLocation else { let sourceLocation = self.sourceLocation else {
return nil return nil
} }
let from = ConstraintItem(target: self.item as AnyObject, attributes: self.attributes) let from = ConstraintItem(target: self.item, attributes: self.attributes)
return Constraint( return Constraint(
from: from, from: from,

View File

@ -28,7 +28,7 @@
#endif #endif
public class ConstraintItem : Equatable { public final class ConstraintItem {
internal weak var target: AnyObject? internal weak var target: AnyObject?
internal let attributes: ConstraintAttributes internal let attributes: ConstraintAttributes

View File

@ -160,20 +160,42 @@ public class ConstraintMaker {
internal static func prepareConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] { internal static func prepareConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] {
let maker = ConstraintMaker(item: item) let maker = ConstraintMaker(item: item)
closure(maker) closure(maker)
let constraints = maker.descriptions var constraints: [Constraint] = []
.map { $0.constraint } for description in maker.descriptions {
.filter { $0 != nil } guard let constraint = description.constraint else {
.map { $0! } continue
}
constraints.append(constraint)
}
return constraints return constraints
} }
internal static func makeConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) { internal static func makeConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) {
let maker = ConstraintMaker(item: item) let maker = ConstraintMaker(item: item)
closure(maker) closure(maker)
let constraints = maker.descriptions var constraints: [Constraint] = []
.map { $0.constraint } for description in maker.descriptions {
.filter { $0 != nil }
.map { $0! } guard let relation = description.relation,
let related = description.related,
let sourceLocation = description.sourceLocation else {
continue
}
let from = ConstraintItem(target: description.item, attributes: description.attributes)
let constraint = Constraint(
from: from,
to: related,
relation: relation,
sourceLocation: sourceLocation,
label: description.label,
multiplier: description.multiplier,
constant: description.constant,
priority: description.priority
)
constraints.append(constraint)
}
for constraint in constraints { for constraint in constraints {
constraint.activateIfNeeded(updatingExisting: false) constraint.activateIfNeeded(updatingExisting: false)
} }
@ -192,10 +214,13 @@ public class ConstraintMaker {
let maker = ConstraintMaker(item: item) let maker = ConstraintMaker(item: item)
closure(maker) closure(maker)
let constraints = maker.descriptions var constraints: [Constraint] = []
.map { $0.constraint } for description in maker.descriptions {
.filter { $0 != nil } guard let constraint = description.constraint else {
.map { $0! } continue
}
constraints.append(constraint)
}
for constraint in constraints { for constraint in constraints {
constraint.activateIfNeeded(updatingExisting: true) constraint.activateIfNeeded(updatingExisting: true)
} }

View File

@ -59,33 +59,33 @@ extension LayoutConstraintItem {
return nil return nil
} }
internal var constraints: [Constraint] { internal var constraints: [Constraint] {
return self.constraintsHashTable.allObjects return self.constraintsSet.allObjects as! [Constraint]
} }
internal func add(constraints: [Constraint]) { internal func add(constraints: [Constraint]) {
let hashTable = self.constraintsHashTable let constraintsSet = NSMutableSet()
for constraint in constraints { for constraint in constraints {
hashTable.add(constraint) constraintsSet.add(constraint)
} }
} }
internal func remove(constraints: [Constraint]) { internal func remove(constraints: [Constraint]) {
let hashTable = self.constraintsHashTable let constraintsSet = NSMutableSet()
for constraint in constraints { for constraint in constraints {
hashTable.remove(constraint) constraintsSet.remove(constraint)
} }
} }
private var constraintsHashTable: NSHashTable<Constraint> { private var constraintsSet: NSMutableSet {
let constraints: NSHashTable<Constraint> let constraintsSet: NSMutableSet
if let existing = objc_getAssociatedObject(self, &constraintsKey) as? NSHashTable<Constraint> { if let existing = objc_getAssociatedObject(self, &constraintsKey) as? NSMutableSet {
constraints = existing constraintsSet = existing
} else { } else {
constraints = NSHashTable<Constraint>() constraintsSet = NSMutableSet()
objc_setAssociatedObject(self, &constraintsKey, constraints, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) objc_setAssociatedObject(self, &constraintsKey, constraintsSet, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
} }
return constraints return constraintsSet
} }