Last active
August 29, 2015 14:15
-
-
Save ttepasse/5e022231f690afe4ac0b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class CostlyAllocatedObject { | |
var description : String | |
init(_ isPrivate: Bool, _ isStarred: Bool, _ isUnread: Bool) { | |
self.description = "<Costly: Private: \(isPrivate), Starred \(isStarred), Unread: \(isUnread)>" | |
} | |
} | |
class ReallocateIfNeeded<T> { | |
private var cachedInstance: T? = nil | |
private var needsReallocation: Bool | |
private var callToAllocateInstance: () -> T | |
init(allocationProcedure: () -> T) { | |
self.needsReallocation = true | |
self.callToAllocateInstance = allocationProcedure | |
} | |
func invalidate() { | |
self.needsReallocation = true | |
} | |
func mayNeedReallocationIf(@autoclosure test: () -> Bool) { | |
if test() { | |
self.invalidate() | |
} | |
} | |
var instance : T { | |
get { | |
if self.needsReallocation { | |
println("(Re)-Allocating Costly") | |
self.cachedInstance = self.callToAllocateInstance() | |
self.needsReallocation = false | |
return self.cachedInstance! | |
} else { | |
println("Returning cached Costly") | |
return self.cachedInstance! | |
} | |
} | |
} | |
} | |
class Usage { | |
var isPrivate: Bool? = nil { | |
didSet { | |
println("isPrivate: comparing new value (\(self.isPrivate!)) to old value (\(oldValue!))") | |
costly.mayNeedReallocationIf( self.isPrivate != oldValue ) | |
} | |
} | |
var isStarred: Bool? = nil { | |
didSet { | |
println("isStarred: comparing new value (\(self.isStarred!)) to old value (\(oldValue!))") | |
costly.mayNeedReallocationIf( self.isStarred != oldValue ) | |
} | |
} | |
var isUnread: Bool? = nil { | |
didSet { | |
println("isUnread: comparing new value (\(self.isUnread!)) to old value (\(oldValue!))") | |
costly.mayNeedReallocationIf( self.isUnread != oldValue ) | |
} | |
} | |
init () { | |
self.isUnread = true | |
self.isStarred = true | |
self.isPrivate = true | |
} | |
// lazy is needed for the presence of self in the allocating closure. | |
// self is an unowned capture to break the reference cycles between Usage -> ReallocateIfNeeded -> Closure -> Us... | |
lazy var costly: ReallocateIfNeeded<CostlyAllocatedObject> = ReallocateIfNeeded { | |
[unowned self] in | |
return CostlyAllocatedObject(self.isPrivate!, self.isStarred!, self.isUnread!) | |
} | |
} | |
let test = Usage() | |
// First Usage | |
test.isPrivate // -> true | |
test.isStarred // -> true | |
test.isUnread // -> true | |
test.costly.instance // (Re)-Allocating Costly | |
// Nothing changed | |
test.isPrivate = true // isPrivate: comparing new value (true) to old value (true) | |
test.costly.instance // Returning cached Costly | |
// Changes galore! | |
test.isPrivate = false // isPrivate: comparing new value (false) to old value (true) | |
test.isStarred = false // isStarred: comparing new value (false) to old value (true) | |
test.isUnread = false // isUnread: comparing new value (false) to old value (true) | |
test.costly.instance // (Re)-Allocating Costly | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment