Besides, sending a notification without parameters is a bit ugly in Objective-C, in Swift this can be done much nicer by encapsulating the notification in an object of its own.
Both the above issues have lead me to implement the following "MergeableNotification" class:
struct MergeableNotification {
private var suspendLevel = 0
private var notificationNeeded = false
private var notificationName: String
private unowned var notificationSourceObject: AnyObject
mutating func post() {
if suspendLevel == 0 {
} else {
}
mutating func merge(closure: () -> () ) {
}
init(name: String, sourceObject: AnyObject) {
self.notificationName = name
self.notificationSourceObject = sourceObject
}
}
private unowned var notificationSourceObject: AnyObject
NSNotificationCenter.defaultCenter().postNotificationName(notificationName, object: notificationSourceObject)
notificationNeeded = true
}}
suspendLevel++
closure()
suspendLevel--
if suspendLevel == 0 && notificationNeeded {
NSNotificationCenter.defaultCenter().postNotificationName(notificationName, object: notificationSourceObject)
notificationNeeded = false
}}
self.notificationName = name
self.notificationSourceObject = sourceObject
}
}
This class is used as follows:
Defining a filtered notification
let LINE_UPDATED_NOTIFICATION = "LineUpdatedNotification"
class DataModel {
var lineUpdatedNotification: MergeableNotification!
init() {
lineUpdatedNotification = MergeableNotification(name: LINE_UPDATED_NOTIFICATION, sourceObject: self)
}
... more
}
If the object sending the notification is self, then we have to define the notification as forced unwrapped and initialise it in the initialiser.
Posting a notification
This is easy:
func removeCharacterAt(index: Int) {
... more
lineUpdatedNotification.post()
}
Merging notifications to prevent a notification storm
This may be a bit unusual if you (like me) are not used to functional programming. The code that can raise notifications is called from within a closure. All the notifications that would be raised in the closure are merged into a single notification that will be fired when the closure end, IF that closure is the top-level closure. I.e. if the call to "merge" is nested, then the inner closures will NOT fire a notification when they terminate.
func moveToLeftEndOfLine() {
{
[unowned self] in
self.removeSelections()
self.addInsertionPoint(self.line.startIndex)
}
)
}
Note that this implementation is not thread safe. But as long as the calls to "merge" are made from within the same thread, even when nested, this should work fine.
Initially I wanted to use a push-pop approach for the nesting of calls to "merge". But that approach has two distinct problems:
1) push and pop are two calls, forget one and you are in trouble. But that trouble could hide itself until the app was in the user's hands.
2) push and pop would need to be called from the same ident level in the code as the code in between. That makes it hard to spot where to start and end the merging.
Using a closure neatly avoids those two problems. And though it necessitates the need to quote 'self' I find that less troubling that the two above problems.
Initially I wanted to use a push-pop approach for the nesting of calls to "merge". But that approach has two distinct problems:
1) push and pop are two calls, forget one and you are in trouble. But that trouble could hide itself until the app was in the user's hands.
2) push and pop would need to be called from the same ident level in the code as the code in between. That makes it hard to spot where to start and end the merging.
Using a closure neatly avoids those two problems. And though it necessitates the need to quote 'self' I find that less troubling that the two above problems.
Happy coding...
Did this help?, then please help out a small independent.
If you decide that you want to make a small donation, you can do so by clicking this
link: a cup of coffee ($2) or use the popup on the right hand side for different amounts.
Payments will be processed by PayPal, receiver will be sales at balancingrock dot nl
Bitcoins will be gladly accepted at: 1GacSREBxPy1yskLMc9de2nofNv2SNdwqH
We don't get the world we wish for... we get the world we pay for.
Did this help?, then please help out a small independent.
If you decide that you want to make a small donation, you can do so by clicking this
link: a cup of coffee ($2) or use the popup on the right hand side for different amounts.
Payments will be processed by PayPal, receiver will be sales at balancingrock dot nl
Bitcoins will be gladly accepted at: 1GacSREBxPy1yskLMc9de2nofNv2SNdwqH
We don't get the world we wish for... we get the world we pay for.
No comments:
Post a Comment