Skip to content

Instantly share code, notes, and snippets.

@muizidn
Last active August 8, 2019 06:10
Show Gist options
  • Save muizidn/3c979eab7c81e3822744e1a9ed35ec05 to your computer and use it in GitHub Desktop.
Save muizidn/3c979eab7c81e3822744e1a9ed35ec05 to your computer and use it in GitHub Desktop.
Log your object lifetime and count. Make sure it never leaked.
#if DEBUG
// By [email protected]
import Foundation
fileprivate var kTracker: UInt = 0
fileprivate var items: [String:Int] = [:]
protocol LifetimeLoggable: AnyObject {
/// Make sure this overridable
static var maxInstanceCount: Int { get }
}
extension LifetimeLoggable {
fileprivate var key: String { return "\(type(of: self))" }
func logLifetime(caller: StaticString = #function) {
assert(caller.description.contains("init("),
"Invoke from init!")
let tracker = Tracker(key: key, type: type(of: self))
objc_setAssociatedObject(self, &kTracker, tracker, .OBJC_ASSOCIATION_RETAIN)
}
}
fileprivate class Tracker {
let key: String
let type: LifetimeLoggable.Type
init(key: String, type: LifetimeLoggable.Type) {
self.key = key
self.type = type
incrementCounter()
}
func incrementCounter() {
var count = items[key] ?? 0
count += 1
assert(count <= type.maxInstanceCount, "You have memory leak my friend 😂. Now you have \(count) instances where you said that maximum instances allowed is \(type.maxInstanceCount) for \(key)")
items[key] = count
print("TRACKER INCREMENT: \(key) = \(count)")
}
func decrementCounter() {
var count = items[key] ?? 0
count -= 1
items[key] = count
print("TRACKER DECREMENT: \(key) = \(count)")
}
deinit { decrementCounter() }
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment