Better Notification & Key Value Observers for Swift.
Simpler API with sensible defaults
Easier to avoid ‘dangling’ observers
Delivers on main thread by default (avoid unexpected concurrency bugs)
Easy activation/deactivation
Simple integration with view controller lifecycles
Installation
HSObserver is available through CocoaPods. To install
it, simply add the following line to your Podfile:
pod 'HSObserver'
Or Install as a swift package
Observers are Released Automatically
class Watcher {
struct Notif {
static let wave = NSNotification.Name.init("waveNotification")
}
var waveObserver:HSObserver
init() {
waveObserver = HSObserver.init(forName: Watcher.Notif.wave,
activate:true,
using: { (notif) in
//Do Something
})
}
}
Unlike a standard observer, waveObserver is fully released when Watcher is released.
(Posting a wave notification will not call the //Do Something code once Watcher is released)
Delivery happens on the main thread
It’s easy to get bitten by notifications unexpectedly arriving on a background thread. In almost all cases - you don’t want that!
.
(you can change this for a given observer if you want to - but you probably shouldn’t)
If you use the initialiser without specifying a queue (the default), then the calling block is marked as @MainActor - so should play nicely with swift async code
Observers can be Activated and Deactivated
var waveObserver:HSObserver
init() {
waveObserver = HSObserver.init(forName: Watcher.Notif.wave,
using: { (notif) in
//Do Something
})
//activate
waveObserver.activate()
//deactivate
waveObserver.deactivate()
}
N.B. Remember that you have to activate your observer for it to work.
either specify activate:true in the initialiser
or call myObserver.activate()`
or chain on the initialiser HSObserver.init(....).activate()
HSHasObservers integrates well with View Controller lifecycle
A common pattern for a view controller is to activate observers in viewWillAppear, and de-activate them in viewDidDisppear
Adding the HSHasObservers protocol to any class allows you to add a group of observers, and activate or deactivate them easily.
Observers can be added manually, or by chaining .add(to:self) to an HSObserver
class ViewController: NSViewController, HSHasObservers {
override func viewDidLoad() {
super.viewDidLoad()
//Add manually
let waveObserver = HSObserver.init(forName: Watcher.Notif.wave,
using: { (notif) in
//Do Something
})
self.add(observer: waveObserver)
//Or by chaining
HSObserver.init(forName: Watcher.Notif.wave,
using: { (notif) in
//Do Something
}).add(to: self)
}
}
let manyThingsObserver = HSObserver.init(forNames: [Watcher.Notif.wave,Watcher.Notif.hello] ,
activate:true,
using: { (notif) in
//Do Something
})
Specify centre, queue, etc
/// Create observer
///
/// - parameter name: notification name
/// - parameter obj: object to observe (default nil)
/// - parameter queue: queue to run the block on (default main)
/// - parameter center: notification center (default NotificationCenter.default)
/// - parameter block: block to run (beware of retain cycles!)
///
/// - returns: unactivated manager. Call activate() to start
convenience init(forName name: NSNotification.Name,
object obj: Any? = nil,
queue: OperationQueue? = .main,
center newCenter: NotificationCenter = NotificationCenter.default,
activate: Bool = false,
using block: @escaping (Notification) -> Swift.Void)
HSObservers lets you skip the defaults. We assume
object = nil
queue = .main
center = NotificationCenter.default
activate = false
you can override each of these in the initialiser
Note that Apple’s default is to call your block on the same queue as the sender. If you want to do this, then just use centre = nil
I find that I typically want to use notifications to update the UI - so my default is to use .main
Brent Simmons has a great article on why you should almost always be using .main
Convenience functions on NSNotification.Name
Post a notification directly
class Watcher {
struct Notif {
static let wave = NSNotification.Name.init("waveNotification")
}
func doPosting() {
Watcher.Notif.wave.post()
//or
Watcher.Notif.wave.post(object:self,userInfo:["Foo":"Bar"])
}
}
Assume the default notification centre and default options when posting directly from NotificationCenter
(I strongly reccomend that you structure your notifications within a Notif struct of the relevant object. It makes things really easy to read)
NotificationCenter.post(Watcher.Notif.wave)
//is equivalent to
NotificationCenter.default.post(Watcher.wave,object:nil)
Now with Key Value Notifications
for example, to observe the duration of an AVPlayerItem
HSObserver
Summary
Better Notification & Key Value Observers for Swift.
Installation
HSObserver is available through CocoaPods. To install it, simply add the following line to your Podfile:
Or Install as a swift package
Observers are Released Automatically
Unlike a standard observer, waveObserver is fully released when Watcher is released.
(Posting a wave notification will not call the
//Do Something
code once Watcher is released)Delivery happens on the main thread
It’s easy to get bitten by notifications unexpectedly arriving on a background thread. In almost all cases - you don’t want that! .
(you can change this for a given observer if you want to - but you probably shouldn’t)
If you use the initialiser without specifying a queue (the default), then the calling block is marked as @MainActor - so should play nicely with swift async code
Observers can be Activated and Deactivated
N.B. Remember that you have to activate your observer for it to work.
activate:true
in the initialiserHSObserver.init(....).activate()
HSHasObservers integrates well with View Controller lifecycle
A common pattern for a view controller is to activate observers in
viewWillAppear
, and de-activate them inviewDidDisppear
Adding the
HSHasObservers
protocol to any class allows you to add a group of observers, and activate or deactivate them easily.Observers can be added manually, or by chaining .add(to:self) to an HSObserver
this works well with the view lifecycle
Add Multiple Observers
Specify centre, queue, etc
HSObservers lets you skip the defaults. We assume
you can override each of these in the initialiser
Note that Apple’s default is to call your block on the same queue as the sender. If you want to do this, then just use centre = nil
I find that I typically want to use notifications to update the UI - so my default is to use .main
Brent Simmons has a great article on why you should almost always be using .main
Convenience functions on NSNotification.Name
Post a notification directly
Assume the default notification centre and default options when posting directly from NotificationCenter (I strongly reccomend that you structure your notifications within a Notif struct of the relevant object. It makes things really easy to read)
Now with Key Value Notifications
for example, to observe the duration of an AVPlayerItem
(again, remember to keep a reference to durationObserver or it will disappear)
Author
ConfusedVorlon, rob@hobbyistsoftware.com
License
HSNotification is available under the MIT license. See the LICENSE file for more info.