In Objective-C ist eine benutzerdefinierte Benachrichtigung nur ein einfacher NSString, in der WWDC-Version von Swift 3 ist jedoch nicht klar, wie sie aussehen sollte.
In Objective-C ist eine benutzerdefinierte Benachrichtigung nur ein einfacher NSString, in der WWDC-Version von Swift 3 ist jedoch nicht klar, wie sie aussehen sollte.
Antworten:
Sie können hierfür auch ein Protokoll verwenden
protocol NotificationName {
var name: Notification.Name { get }
}
extension RawRepresentable where RawValue == String, Self: NotificationName {
var name: Notification.Name {
get {
return Notification.Name(self.rawValue)
}
}
}
Und definieren Sie dann Ihre Benachrichtigungsnamen als eine enum
beliebige Stelle. Beispielsweise:
class MyClass {
enum Notifications: String, NotificationName {
case myNotification
}
}
Und benutze es gerne
NotificationCenter.default.post(name: Notifications.myNotification.name, object: nil)
Auf diese Weise werden die Benachrichtigungsnamen von der Stiftung entkoppelt Notification.Name
. Und Sie müssen Ihr Protokoll nur ändern, wenn die Implementierung fürNotification.Name
Änderungen vorsieht.
NotificationName
sodass die name
Eigenschaft nur zu den Aufzählungen hinzugefügt wird, die dem Protokoll entsprechen.
extension NotificationName where Self: RawRepresentable, Self.RawValue == String {
Es gibt einen saubereren (glaube ich) Weg, dies zu erreichen
extension Notification.Name {
static let onSelectedSkin = Notification.Name("on-selected-skin")
}
Und dann können Sie es so verwenden
NotificationCenter.default.post(name: .onSelectedSkin, object: selectedSkin)
extension NSNotification.Name
statt extension Notification.Name
. Ansonsten Swift 3 Beschwerden mit'Notification' is ambiguous for type lookup in this context
Notification.post ist definiert als:
public func post(name aName: NSNotification.Name, object anObject: AnyObject?)
In Objective-C ist der Benachrichtigungsname ein einfacher NSString. In Swift ist es als NSNotification.Name definiert.
NSNotification.Name ist definiert als:
public struct Name : RawRepresentable, Equatable, Hashable, Comparable {
public init(_ rawValue: String)
public init(rawValue: String)
}
Dies ist etwas seltsam, da ich erwarten würde, dass es sich um eine Aufzählung handelt und nicht um eine benutzerdefinierte Struktur, die anscheinend keinen Nutzen mehr hat.
In Notification for NSNotification.Name gibt es einen Typealias.
public typealias Name = NSNotification.Name
Der verwirrende Teil ist, dass sowohl Benachrichtigung als auch NS-Benachrichtigung in Swift vorhanden sind
Um Ihre eigene benutzerdefinierte Benachrichtigung zu definieren, gehen Sie wie folgt vor:
public class MyClass {
static let myNotification = Notification.Name("myNotification")
}
Dann um es zu nennen:
NotificationCenter.default().post(name: MyClass.myNotification, object: self)
Notification.Name
es sich um eine Aufzählung handelt, kann niemand neue Benachrichtigungen definieren. Wir verwenden Strukturen für ansonsten enumähnliche Typen, die das Hinzufügen neuer Mitglieder ermöglichen müssen. (Siehe den Vorschlag zur schnellen Entwicklung .)
Notification
ist ein Werttyp (eine Struktur), so dass er von Swifts Semantik für Wert (im) Mutabilität profitieren kann. Im Allgemeinen löschen Foundation-Typen ihre "NS" in Swift 3, aber wenn einer der neuen Foundation-Werttypen vorhanden ist, um ihn zu ersetzen, bleibt der alte Referenztyp erhalten (wobei der Name "NS" beibehalten wird), sodass Sie ihn weiterhin verwenden können, wenn Sie benötigen eine Referenzsemantik oder eine Unterklasse. Siehe den Vorschlag .
Einfacherer Weg:
let name:NSNotification.Name = NSNotification.Name("notificationName")
NotificationCenter.default.post(name: name, object: nil)
Sie können NSNotification.Name einen benutzerdefinierten Initialisierer hinzufügen
extension NSNotification.Name {
enum Notifications: String {
case foo, bar
}
init(_ value: Notifications) {
self = NSNotification.Name(value.rawValue)
}
}
Verwendung:
NotificationCenter.default.post(name: Notification.Name(.foo), object: nil)
case
s in einer Aufzählung sollte in Kleinbuchstaben geschrieben werden, nicht die Aufzählung selbst. Typnamen werden in Großbuchstaben geschrieben und Aufzählungen sind Typen.
Ich kann eine andere Option vorschlagen, die der von @CesarVarela vorgeschlagenen ähnelt.
extension Notification.Name {
static var notificationName: Notification.Name {
return .init("notificationName")
}
}
Auf diese Weise können Sie Benachrichtigungen einfach veröffentlichen und abonnieren.
NotificationCenter.default.post(Notification(name: .notificationName))
Hoffe das wird dir helfen.
Ich habe meine eigene Implementierung durchgeführt, um die Dinge von dort und dort zu mischen, und finde dies am bequemsten. Teilen für wen auch immer das interessiert sein könnte:
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")
Dies ist nur eine Referenz
// 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)
Der Vorteil der Verwendung von Aufzählungen besteht darin, dass der Compiler überprüft, ob der Name korrekt ist. Reduziert potenzielle Probleme und erleichtert das Refactoring.
Für diejenigen, die Enums anstelle von Anführungszeichen für Benachrichtigungsnamen verwenden möchten, ist dieser Code genau das Richtige:
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)
}
}
Dann können Sie es so verwenden:
NotificationCenter.default.post(.somethingHappened)
Obwohl dies nichts mit der Frage zu tun hat, kann dies auch mit Storyboard-Abschnitten geschehen, um die Eingabe von Zeichenfolgen in Anführungszeichen zu vermeiden:
enum StoryboardSegue: String {
case toHere
case toThere
case unwindToX
}
extension UIViewController {
func perform(segue: StoryboardSegue) {
performSegue(withIdentifier: segue.rawValue, sender: self)
}
}
Nennen Sie es dann auf Ihrem View Controller wie folgt:
perform(segue: .unwindToX)
Wenn Sie benutzerdefinierte Benachrichtigungen nur für Zeichenfolgen verwenden, gibt es keinen Grund, Klassen zu erweitern String
extension String {
var notificationName : Notification.Name{
return Notification.Name.init(self)
}
}
Wenn Sie möchten, dass dies in einem Projekt, das gleichzeitig Objective-C und Swift verwendet, sauber funktioniert, war es für mich einfacher, die Benachrichtigungen in Objective-C zu erstellen.
Erstellen Sie eine .m / .h-Datei:
//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";
In Ihrem MyProject-Bridging-Header.h
(nach Ihrem Projekt benannt), um sie Swift auszusetzen.
#import "CustomNotifications.h"
Verwenden Sie Ihre Benachrichtigungen in Objective-C wie folgt:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(yourMethod:) name:yourNotificationName:nil];
Und in Swift (5) so:
NotificationCenter.default.addObserver(self, selector: #selector(yourMethod(sender:)), name: .yourNotificationName, object: nil)