From eb107818acc691af7054e534e8beee19842935e4 Mon Sep 17 00:00:00 2001 From: Robert Payne Date: Thu, 24 Nov 2016 00:03:41 +1300 Subject: [PATCH] Fix Memory Leaks --- Source/Constraint.swift | 6 ++-- Source/ConstraintDescription.swift | 2 +- Source/ConstraintItem.swift | 2 +- Source/ConstraintMaker.swift | 49 ++++++++++++++++++++++-------- Source/LayoutConstraintItem.swift | 24 +++++++-------- 5 files changed, 55 insertions(+), 28 deletions(-) diff --git a/Source/Constraint.swift b/Source/Constraint.swift index 3c2c242..858490d 100644 --- a/Source/Constraint.swift +++ b/Source/Constraint.swift @@ -27,7 +27,8 @@ import AppKit #endif -public class Constraint { +@objc(SnapKitConstraint) +public final class Constraint : NSObject { internal let sourceLocation: (String, UInt) internal let label: String? @@ -67,6 +68,7 @@ public class Constraint { self.constant = constant self.priority = priority self.layoutConstraints = [] + super.init() // get attributes let layoutFromAttributes = self.from.attributes.layoutAttributes @@ -260,7 +262,7 @@ public class Constraint { } for layoutConstraint in layoutConstraints { - let existingLayoutConstraint = existingLayoutConstraints.first { $0.canUpdate(constraint: layoutConstraint) } + let existingLayoutConstraint = existingLayoutConstraints.first { $0 == layoutConstraint } guard let updateLayoutConstraint = existingLayoutConstraint else { fatalError("Updated constraint could not find existing matching constraint to update: \(layoutConstraint)") } diff --git a/Source/ConstraintDescription.swift b/Source/ConstraintDescription.swift index a6f12b7..3521f9f 100644 --- a/Source/ConstraintDescription.swift +++ b/Source/ConstraintDescription.swift @@ -45,7 +45,7 @@ public class ConstraintDescription { let sourceLocation = self.sourceLocation else { return nil } - let from = ConstraintItem(target: self.item as AnyObject, attributes: self.attributes) + let from = ConstraintItem(target: self.item, attributes: self.attributes) return Constraint( from: from, diff --git a/Source/ConstraintItem.swift b/Source/ConstraintItem.swift index de0e175..a342c1d 100644 --- a/Source/ConstraintItem.swift +++ b/Source/ConstraintItem.swift @@ -28,7 +28,7 @@ #endif -public class ConstraintItem : Equatable { +public final class ConstraintItem { internal weak var target: AnyObject? internal let attributes: ConstraintAttributes diff --git a/Source/ConstraintMaker.swift b/Source/ConstraintMaker.swift index 9232262..022a60d 100644 --- a/Source/ConstraintMaker.swift +++ b/Source/ConstraintMaker.swift @@ -160,20 +160,42 @@ public class ConstraintMaker { internal static func prepareConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] { let maker = ConstraintMaker(item: item) closure(maker) - let constraints = maker.descriptions - .map { $0.constraint } - .filter { $0 != nil } - .map { $0! } + var constraints: [Constraint] = [] + for description in maker.descriptions { + guard let constraint = description.constraint else { + continue + } + constraints.append(constraint) + } return constraints } internal static func makeConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) { let maker = ConstraintMaker(item: item) closure(maker) - let constraints = maker.descriptions - .map { $0.constraint } - .filter { $0 != nil } - .map { $0! } + var constraints: [Constraint] = [] + for description in maker.descriptions { + + 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 { constraint.activateIfNeeded(updatingExisting: false) } @@ -192,10 +214,13 @@ public class ConstraintMaker { let maker = ConstraintMaker(item: item) closure(maker) - let constraints = maker.descriptions - .map { $0.constraint } - .filter { $0 != nil } - .map { $0! } + var constraints: [Constraint] = [] + for description in maker.descriptions { + guard let constraint = description.constraint else { + continue + } + constraints.append(constraint) + } for constraint in constraints { constraint.activateIfNeeded(updatingExisting: true) } diff --git a/Source/LayoutConstraintItem.swift b/Source/LayoutConstraintItem.swift index 9260e76..2f4c65d 100644 --- a/Source/LayoutConstraintItem.swift +++ b/Source/LayoutConstraintItem.swift @@ -59,33 +59,33 @@ extension LayoutConstraintItem { return nil } internal var constraints: [Constraint] { - return self.constraintsHashTable.allObjects + return self.constraintsSet.allObjects as! [Constraint] } internal func add(constraints: [Constraint]) { - let hashTable = self.constraintsHashTable + let constraintsSet = NSMutableSet() for constraint in constraints { - hashTable.add(constraint) + constraintsSet.add(constraint) } } internal func remove(constraints: [Constraint]) { - let hashTable = self.constraintsHashTable + let constraintsSet = NSMutableSet() for constraint in constraints { - hashTable.remove(constraint) + constraintsSet.remove(constraint) } } - private var constraintsHashTable: NSHashTable { - let constraints: NSHashTable + private var constraintsSet: NSMutableSet { + let constraintsSet: NSMutableSet - if let existing = objc_getAssociatedObject(self, &constraintsKey) as? NSHashTable { - constraints = existing + if let existing = objc_getAssociatedObject(self, &constraintsKey) as? NSMutableSet { + constraintsSet = existing } else { - constraints = NSHashTable() - objc_setAssociatedObject(self, &constraintsKey, constraints, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + constraintsSet = NSMutableSet() + objc_setAssociatedObject(self, &constraintsKey, constraintsSet, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } - return constraints + return constraintsSet }