Improvised KVO
/* | |
ObservationHelper.swift is published under the MIT License. | |
Copyright (C) 2014-15, Roopesh Chander http://roopc.net/ | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files (the "Software"), to deal | |
in the Software without restriction, including without limitation the rights | |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the Software is | |
furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in | |
all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
THE SOFTWARE. | |
*/ | |
// Usage: | |
// var observer1 = object.onChange("property") { change in | |
// doSomethingWithChangeDict(change) | |
// } | |
// var observer2 = object.onNotification(NSMetadataQueryDidFinishGatheringNotification) { | |
// notification in | |
// doSomethingWithNotificationDict(notification.userInfo) | |
// } | |
// // Keep a strong reference to the returned observer objects | |
// // as long as you want to observe said thingie. | |
import Foundation | |
extension NSObject { | |
func onChange(keyPath: String, options: NSKeyValueObservingOptions, | |
runBlock block: (change: [NSObject : AnyObject]!) -> ()) -> AnyObject { | |
return KeyValueObserver(object: self, keyPath: keyPath, options: options, block: block) | |
as AnyObject | |
} | |
func onChange(keyPath: String, | |
runBlock block: (change: [NSObject : AnyObject]!) -> ()) -> AnyObject { | |
return KeyValueObserver(object: self, keyPath: keyPath, options: nil, block: block) | |
as AnyObject | |
} | |
func onChangeInAnyOf(keyPaths: [String], options: NSKeyValueObservingOptions, | |
runBlock block: (keyPath: String, change: [NSObject : AnyObject]!) -> ()) -> AnyObject { | |
return KeyValueObserverMultiKey(object: self, keyPaths: keyPaths, options: options, block: block) | |
as AnyObject | |
} | |
func onChangeInAnyOf(keyPaths: [String], | |
runBlock block: (keyPath: String, change: [NSObject : AnyObject]!) -> ()) -> AnyObject { | |
return KeyValueObserverMultiKey(object: self, keyPaths: keyPaths, options: nil, block: block) | |
as AnyObject | |
} | |
func onNotification(name: String, runBlock block: ((NSNotification!) -> ())) -> AnyObject { | |
return NotificationObserver(object: self, name: name, queue: NSOperationQueue.currentQueue(), block: block) | |
as AnyObject | |
} | |
} | |
func onGenericNotification(name: String, runBlock block: ((NSNotification!) -> ())) -> AnyObject { | |
return NotificationObserver(object: nil, name: name, queue: NSOperationQueue.currentQueue(), block: block) | |
as AnyObject | |
} | |
private class KeyValueObserver: NSObject { | |
weak var _object: NSObject? | |
var _keyPath: String | |
var _block: (change: [NSObject : AnyObject]!) -> () | |
init(object: NSObject, keyPath: String, options: NSKeyValueObservingOptions, | |
block: (change: [NSObject : AnyObject]!) -> ()) { | |
_object = object | |
_keyPath = keyPath | |
_block = block | |
super.init() | |
object.addObserver(self, forKeyPath: keyPath, options: options, context: nil) | |
} | |
override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, | |
change: [NSObject : AnyObject], context: UnsafeMutablePointer<()>) { | |
assert(keyPath == _keyPath) | |
_block(change: change) | |
} | |
deinit { | |
_object?.removeObserver(self, forKeyPath: _keyPath, context: nil) | |
} | |
} | |
private class KeyValueObserverMultiKey: NSObject { | |
weak var _object: NSObject? | |
var _keyPaths: [String] | |
var _block: (keyPath: String, change: [NSObject : AnyObject]!) -> () | |
init(object: NSObject, keyPaths: [String], options: NSKeyValueObservingOptions, | |
block: (keyPath: String, change: [NSObject : AnyObject]!) -> ()) { | |
_object = object | |
_keyPaths = keyPaths | |
_block = block | |
super.init() | |
for keyPath in keyPaths { | |
object.addObserver(self, forKeyPath: keyPath, options: options, context: nil) | |
} | |
} | |
override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, | |
change: [NSObject : AnyObject], context: UnsafeMutablePointer<()>) { | |
_block(keyPath: keyPath, change: change) | |
} | |
deinit { | |
for keyPath in _keyPaths { | |
_object?.removeObserver(self, forKeyPath: keyPath, context: nil) | |
} | |
} | |
} | |
private class NotificationObserver: NSObject { | |
var _observerObject: AnyObject? | |
init(object: NSObject?, name: String!, queue: NSOperationQueue!, | |
block: ((NSNotification!) -> ())) { | |
super.init() | |
_observerObject = NSNotificationCenter.defaultCenter().addObserverForName(name, object: object, | |
queue: queue, usingBlock: block) | |
} | |
deinit { | |
if let observer: AnyObject = _observerObject { | |
NSNotificationCenter.defaultCenter().removeObserver(observer) | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment