Respostas:
Você também pode usar um protocolo para este
protocol NotificationName {
var name: Notification.Name { get }
}
extension RawRepresentable where RawValue == String, Self: NotificationName {
var name: Notification.Name {
get {
return Notification.Name(self.rawValue)
}
}
}
Em seguida, defina seus nomes de notificação como em enum
qualquer lugar que desejar. Por exemplo:
class MyClass {
enum Notifications: String, NotificationName {
case myNotification
}
}
E usar como
NotificationCenter.default.post(name: Notifications.myNotification.name, object: nil)
Desta forma, os nomes das notificações serão dissociados da Fundação Notification.Name
. E você só terá que modificar seu protocolo no caso da implementação para Notification.Name
alterações.
NotificationName
que oname
propriedade só seja adicionada às enums que estão em conformidade com o protocolo.
extension NotificationName where Self: RawRepresentable, Self.RawValue == String {
Existe uma maneira mais limpa (eu acho) de conseguir isso
extension Notification.Name {
static let onSelectedSkin = Notification.Name("on-selected-skin")
}
E então você pode usá-lo assim
NotificationCenter.default.post(name: .onSelectedSkin, object: selectedSkin)
extension NSNotification.Name
em vez de extension Notification.Name
. Caso contrário, Swift 3 reclama com'Notification' is ambiguous for type lookup in this context
Notification.post é definido como:
public func post(name aName: NSNotification.Name, object anObject: AnyObject?)
Em Objective-C, o nome da notificação é um NSString simples. Em Swift, é definido como NSNotification.Name.
NSNotification.Name é definido como:
public struct Name : RawRepresentable, Equatable, Hashable, Comparable {
public init(_ rawValue: String)
public init(rawValue: String)
}
Isso é meio estranho, já que eu esperava que fosse um Enum, e não uma estrutura personalizada com aparentemente nenhum benefício.
Há um typealias em Notification for NSNotification.Name:
public typealias Name = NSNotification.Name
A parte confusa é que tanto a Notificação quanto a NSNotification existem no Swift
Portanto, para definir sua própria notificação personalizada, faça algo como:
public class MyClass {
static let myNotification = Notification.Name("myNotification")
}
Então, para chamá-lo:
NotificationCenter.default().post(name: MyClass.myNotification, object: self)
Notification.Name
fosse um enum, ninguém seria capaz de definir novas notificações. Usamos structs para tipos do tipo enum que precisam permitir a adição de novos membros. (Veja a proposta de evolução rápida .)
Notification
é um tipo de valor (uma estrutura), de modo que pode se beneficiar da semântica do Swift para (im) mutabilidade de valor. Geralmente, os tipos de base estão perdendo seus "NS" no Swift 3, mas onde um dos novos Tipos de valor de base existe para substituí-lo, o tipo de referência antigo permanece (mantendo o nome "NS") para que você ainda possa usá-lo quando você precisa de semântica de referência ou subclasse. Veja a proposta .
Maneira mais fácil:
let name:NSNotification.Name = NSNotification.Name("notificationName")
NotificationCenter.default.post(name: name, object: nil)
Você pode adicionar um inicializador personalizado a NSNotification.Name
extension NSNotification.Name {
enum Notifications: String {
case foo, bar
}
init(_ value: Notifications) {
self = NSNotification.Name(value.rawValue)
}
}
Uso:
NotificationCenter.default.post(name: Notification.Name(.foo), object: nil)
case
s em um enum deve ser minúsculo, não o próprio enum. Nomes de tipo são maiúsculos e enums são tipos.
Posso sugerir outra opção semelhante à sugerida por @CesarVarela.
extension Notification.Name {
static var notificationName: Notification.Name {
return .init("notificationName")
}
}
Isso permitirá que você poste e se inscreva em notificações facilmente.
NotificationCenter.default.post(Notification(name: .notificationName))
Espero que isso ajude você.
Fiz minha própria implementação misturando coisas de lá e de lá, e achei isso o mais conveniente. Compartilhando para quem possa estar interessado:
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)
}
}
NSNotification.Name(rawValue: "myNotificationName")
Isso é apenas referência
// 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)
A vantagem de usar enums é que fazemos com que o compilador verifique se o nome está correto. Reduz possíveis problemas e facilita a refatoração.
Para quem gosta de usar enums em vez de strings entre aspas para nomes de notificação, este código funciona:
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)
}
}
Então você pode usá-lo assim:
NotificationCenter.default.post(.somethingHappened)
Embora não relacionado à pergunta, o mesmo pode ser feito com segues de storyboard, para evitar digitar strings entre aspas:
enum StoryboardSegue: String {
case toHere
case toThere
case unwindToX
}
extension UIViewController {
func perform(segue: StoryboardSegue) {
performSegue(withIdentifier: segue.rawValue, sender: self)
}
}
Então, em seu controlador de visualização, chame-o assim:
perform(segue: .unwindToX)
se você usar notificações personalizadas apenas de string, não há razão para estender nenhuma classe, mas String
extension String {
var notificationName : Notification.Name{
return Notification.Name.init(self)
}
}
Se você quiser que isso funcione de forma limpa em um projeto que usa Objective-C e Swift ao mesmo tempo, achei mais fácil criar as notificações em Objective-C.
Crie um arquivo .m / .h:
//CustomNotifications.h
#import <Foundation/Foundation.h>
// Add all notifications here
extern const NSNotificationName yourNotificationName;
//CustomNotifications.m
#import "CustomNotifications.h"
// Add their string values here
const NSNotificationName yourNotificationName = @"your_notification_as_string";
Em seu MyProject-Bridging-Header.h
(nome de seu projeto) para expô-los ao Swift.
#import "CustomNotifications.h"
Use suas notificações em Objective-C assim:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(yourMethod:) name:yourNotificationName:nil];
E em Swift (5) assim:
NotificationCenter.default.addObserver(self, selector: #selector(yourMethod(sender:)), name: .yourNotificationName, object: nil)