How do you create custom notifications in Swift 3?
Solution 1
You could also use a protocol for this
protocol NotificationName {
var name: Notification.Name { get }
}
extension RawRepresentable where RawValue == String, Self: NotificationName {
var name: Notification.Name {
get {
return Notification.Name(self.rawValue)
}
}
}
And then define your notification names as an enum
anywhere you want. For example:
class MyClass {
enum Notifications: String, NotificationName {
case myNotification
}
}
And use it like
NotificationCenter.default.post(name: Notifications.myNotification.name, object: nil)
This way the notification names will be decoupled from the Foundation Notification.Name
. And you will only have to modify your protocol in case the implementation for Notification.Name
changes.
Solution 2
There is a cleaner (I think) way to achieve it
extension Notification.Name {
static let onSelectedSkin = Notification.Name("on-selected-skin")
}
And then you can use it like this
NotificationCenter.default.post(name: .onSelectedSkin, object: selectedSkin)
Solution 3
Notification.post is defined as:
public func post(name aName: NSNotification.Name, object anObject: AnyObject?)
In Objective-C, the notification name is a plain NSString. In Swift, it's defined as NSNotification.Name.
NSNotification.Name is defined as:
public struct Name : RawRepresentable, Equatable, Hashable, Comparable {
public init(_ rawValue: String)
public init(rawValue: String)
}
This is kind of weird, since I would expect it to be an Enum, and not some custom struct with seemingly no more benefit.
There is a typealias in Notification for NSNotification.Name:
public typealias Name = NSNotification.Name
The confusing part is that both Notification and NSNotification exist in Swift
So in order to define your own custom notification, do somethine like:
public class MyClass {
static let myNotification = Notification.Name("myNotification")
}
Then to call it:
NotificationCenter.default().post(name: MyClass.myNotification, object: self)
Solution 4
Easier way:
let name:NSNotification.Name = NSNotification.Name("notificationName")
NotificationCenter.default.post(name: name, object: nil)
Solution 5
I may suggest another option which is similar to what @CesarVarela suggested.
extension Notification.Name {
static var notificationName: Notification.Name {
return .init("notificationName")
}
}
This will let you post and subscribe on notifications easily.
NotificationCenter.default.post(Notification(name: .notificationName))
Hope this will help you.
![hexdreamer](https://i.stack.imgur.com/VUjqZ.png?s=256&g=1)
hexdreamer
Updated on July 27, 2020Comments
-
hexdreamer almost 4 years
In Objective-C, a custom notification is just a plain NSString, but it's not obvious in the WWDC version of Swift 3 just what it should be.
-
rickster about 8 yearsGood answer. Some comments: This is kind of weird, since I would expect it to be an Enum — An enum is a closed set. If
Notification.Name
were an enum, nobody would be able to define new notifications. We use structs for otherwise-enum-like types that need to allow adding new members. (See the swift-evolution proposal.) -
rickster about 8 yearsThe confusing part is that both Notification and NSNotification exist in Swift —
Notification
is a value type (a struct), so that it can benefit from Swift's semantics for value (im)mutability. Generally, Foundation types are dropping their "NS" in Swift 3, but where one of the new Foundation Value Types exists to supplant it, the old reference type sticks around (keeping the "NS" name) so that you can still use it when you need reference semantics or to subclass it. See the proposal. -
hexdreamer about 8 yearsLet me clarify: I expect notification names to be enums, like Errors are. You can define your own Error enums, and make them conform to ErrorType.
-
rickster about 8 yearsTrue — Apple could at least theoretically have made NotoficationName (or some such) a protocol, to which you create conforming types. I dunno, but there's likely a reason they didn't... Probably something to do with ObjC bridging? File a bug (to open source, Foundation Swift is in the open) if you've got a better solution worked out.
-
Sean G almost 8 yearsIn your solution you capitalize the declaration of
MyNotification
. Apple's rewrite of their notifications does the same thing. Any idea why this is? As far as I can tell the Swift 3 style guide only suggests capitalizing for protocols and classes. But these are static properties. -
hexdreamer almost 8 yearsYou are probably correct in that it should begin with lowercase.
-
Cesar Varela almost 8 yearsI'm using the code above. This is a static property.
-
0xT0mT0m over 7 yearsVery clean, I like it alot
-
lluisgh over 7 years
extension NSNotification.Name
instead ofextension Notification.Name
. Otherwise Swift 3 complaints with'Notification' is ambiguous for type lookup in this context
-
Jalakoo over 7 yearsLower case 'enum type' and 'init(_ type: type)' for Swift 3.0.2
-
Dorian Roy over 7 yearsYou get my upvote for making a typo in the string and thus demonstrating the value of typed notification names :P
-
hexdreamer over 7 yearsThis is exactly they way I originally thought it should work - notifications should be enums. Thanks for the trick!
-
halil_g over 7 yearsNo problem! I edited the code to include conformation of the extension to
NotificationName
so thename
property is only added to the enums that conform to the protocol. -
jlj over 7 yearsStrictly equivalent but more logical IMO, you can define the extension on NotificationName (instead of RawRepresentable) like this:
extension NotificationName where Self: RawRepresentable, Self.RawValue == String {
-
Leon about 7 yearsIt might be worth noting that this is the method suggested by Apple in WWDC 2016 Session 207 developer.apple.com/videos/play/wwdc2016/207
-
manmal about 7 years@Jalakoo Only the
case
s in an enum should be lowercased, not the enum itself. Type names are uppercased, and enums are types. -
shim over 6 yearsIf using
Notification.Name
as opposed to the Objective-CNSNotification.Name
you should note thatNotificationCenter.post
now expects an object of typeNotification
. Posting looks like this:NotificationCenter.default.post(Notification(.onSelectedSkin, object: selectedSkin))
. May appear more verbose, but it does make more sense verb-wise to post aNotification
directly rather than a name of a notification. Not sure what version of Swift this started in, but I'm still in 3.2. -
Kamil Harasimowicz over 6 years@lluisgh no extra errors in Swift4,
extension Notification.Name
is enough -
Admin about 6 years>
NotificationCenter.default.post(.somethingHappened)
This throws an error; the methods you added in your extension accept more arguments. -
Jonny over 5 yearsNice, although I guess the string names have the risk of redundant values.
-
nickdnk almost 4 yearsI had to extend NSNotification.Name in order to achieve this with Swift 5.
-
Mia over 2 yearsNotification.Name("myNotificationName")