En Objective-C, une notification personnalisée n’est qu’une simple NSString, mais la version WWDC de Swift 3 n’est pas évidente.
Vous pouvez aussi utiliser un protocole pour cela
protocol NotificationName {
var name: Notification.Name { get }
}
extension RawRepresentable where RawValue == String, Self: NotificationName {
var name: Notification.Name {
get {
return Notification.Name(self.rawValue)
}
}
}
Et ensuite, définissez vos noms de notification en tant que enum
où vous voulez. Par exemple:
class MyClass {
enum Notifications: String, NotificationName {
case myNotification
}
}
Et l'utiliser comme
NotificationCenter.default.post(name: Notifications.myNotification.name, object: nil)
De cette façon, les noms des notifications seront découplés du Foundation Notification.Name
. Et vous ne devrez modifier votre protocole qu'au cas où la mise en œuvre de Notification.Name
changerait.
Il y a un moyen plus propre (je pense) d'y parvenir
extension Notification.Name {
static let onSelectedSkin = Notification.Name("on-selected-skin")
}
Et puis vous pouvez l'utiliser comme ça
NotificationCenter.default.post(name: .onSelectedSkin, object: selectedSkin)
Notification.post est défini comme:
public func post(name aName: NSNotification.Name, object anObject: AnyObject?)
En Objective-C, le nom de la notification est un NSString en clair. Dans Swift, il est défini comme NSNotification.Name.
NSNotification.Name est défini comme:
public struct Name : RawRepresentable, Equatable, Hashable, Comparable {
public init(_ rawValue: String)
public init(rawValue: String)
}
C'est un peu étrange, car je m'attendrais à ce que ce soit un Enum, et non une structure personnalisée avec apparemment plus d'avantages.
Il y a un typealias dans Notification pour NSNotification.Name:
public typealias Name = NSNotification.Name
La partie déroutante est qu’il existe à la fois Notification et NSNotification dans Swift.
Donc, afin de définir votre propre notification personnalisée, procédez comme suit:
public class MyClass {
static let myNotification = Notification.Name("myNotification")
}
Puis l'appeler:
NotificationCenter.default().post(name: MyClass.myNotification, object: self)
Manière plus facile:
let name:NSNotification.Name = NSNotification.Name("notificationName")
NotificationCenter.default.post(name: name, object: nil)
Vous pouvez ajouter un initialiseur personnalisé à NSNotification.Name
extension NSNotification.Name {
enum Notifications: String {
case foo, bar
}
init(_ value: Notifications) {
self = NSNotification.Name(value.rawValue)
}
}
Usage:
NotificationCenter.default.post(name: Notification.Name(.foo), object: nil)
J'ai fait ma propre mise en œuvre en mélangeant des choses de part et d'autre, et je trouve cela le plus pratique. Partage pour qui cela pourrait intéresser:
public extension Notification {
public class MyApp {
public static let Something = Notification.Name("Notification.MyApp.Something")
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self,
selector: #selector(self.onSomethingChange(notification:)),
name: Notification.MyApp.Something,
object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
@IBAction func btnTapped(_ sender: UIButton) {
NotificationCenter.default.post(name: Notification.MyApp.Something,
object: self,
userInfo: [Notification.MyApp.Something:"foo"])
}
func onSomethingChange(notification:NSNotification) {
print("notification received")
let userInfo = notification.userInfo!
let key = Notification.MyApp.Something
let something = userInfo[key]! as! String //Yes, this works :)
print(something)
}
}
Je peux suggérer une autre option semblable à celle suggérée par @CesarVarela.
extension Notification.Name {
static var notificationName: Notification.Name {
return .init("notificationName")
}
}
Cela vous permettra de poster et de vous abonner facilement aux notifications.
NotificationCenter.default.post(Notification(name: .notificationName))
J'espère que ceci vous aidera.
NSNotification.Name(rawValue: "myNotificationName")
C'est juste référence
// Add observer:
NotificationCenter.default.addObserver(self,
selector: #selector(notificationCallback),
name: MyClass.myNotification,
object: nil)
// Post notification:
let userInfo = ["foo": 1, "bar": "baz"] as [String: Any]
NotificationCenter.default.post(name: MyClass.myNotification,
object: nil,
userInfo: userInfo)
L'avantage d'utiliser enums est que nous demandons au compilateur de vérifier que le nom est correct. Réduit les problèmes potentiels et facilite la refactorisation.
Pour ceux qui aiment utiliser des énumérations au lieu de chaînes entre guillemets pour les noms de notification, ce code fait l'affaire:
enum MyNotification: String {
case somethingHappened
case somethingElseHappened
case anotherNotification
case oneMore
}
extension NotificationCenter {
func add(observer: Any, selector: Selector,
notification: MyNotification, object: Any? = nil) {
addObserver(observer, selector: selector,
name: Notification.Name(notification.rawValue),
object: object)
}
func post(notification: MyNotification,
object: Any? = nil, userInfo: [AnyHashable: Any]? = nil) {
post(name: NSNotification.Name(rawValue: notification.rawValue),
object: object, userInfo: userInfo)
}
}
Ensuite, vous pouvez l'utiliser comme ceci:
NotificationCenter.default.post(.somethingHappened)
Bien que cela ne soit pas lié à la question, la même chose peut être faite avec les légendes du storyboard, pour éviter de taper des chaînes entre guillemets:
enum StoryboardSegue: String {
case toHere
case toThere
case unwindToX
}
extension UIViewController {
func perform(segue: StoryboardSegue) {
performSegue(withIdentifier: segue.rawValue, sender: self)
}
}
Ensuite, sur votre contrôleur de vue, appelez-le comme suit:
perform(segue: .unwindToX)
si vous utilisez des notifications personnalisées composées uniquement de chaînes, il n'y a aucune raison d'étendre des classes mais String
extension String {
var notificationName : Notification.Name{
return Notification.Name.init(self)
}
}
La réponse de @ CesarVarela est bonne, mais pour rendre le code légèrement plus propre, vous pouvez procéder comme suit:
extension Notification.Name {
typealias Name = Notification.Name
static let onSelectedSkin = Name("on-selected-skin")
static let onFoo = Name("on-foo")
}