Odpowiedz

18

Można również użyć protokołu do tego

protocol NotificationName { 
    var name: Notification.Name { get } 
} 

extension RawRepresentable where RawValue == String, Self: NotificationName { 
    var name: Notification.Name { 
     get { 
      return Notification.Name(self.rawValue) 
     } 
    } 
} 

a następnie zdefiniować swoje nazwiska powiadomień jako enum gdziekolwiek chcesz . Na przykład:

class MyClass { 
    enum Notifications: String, NotificationName { 
     case myNotification 
    } 
} 

i używać go jak

NotificationCenter.default.post(name: Notifications.myNotification.name, object: nil) 

ten sposób nazwy powiadomień zostanie oddzielona od Fundacji Notification.Name. I będziesz musiał tylko zmodyfikować swój protokół w przypadku zmiany implementacji dla Notification.Name.

+0

To jest dokładnie sposób, w jaki początkowo sądziłem, że powinno działać - powiadomienia powinny być wyliczone. Dzięki za podstęp! – hexdreamer

+0

Nie ma problemu! Zmodyfikowalem kod tak, aby zawierał konformację rozszerzenia na 'NotificationName', więc własność' name' jest dodawana tylko do wyliczeń zgodnych z protokołem. –

+0

Ściśle równoważne, ale bardziej logiczne IMO, można zdefiniować rozszerzenie na NotificationName (zamiast RawRepresentable) w ten sposób: 'extension NotificationName gdzie Self: RawRepresentable, Self.RawValue == String {' – jlj

31

Notification.post jest zdefiniowany jako:

public func post(name aName: NSNotification.Name, object anObject: AnyObject?) 

W celu C nazwa zgłoszenie jest zwykły NSString. W Swift jest zdefiniowany jako NSNotification.Name.

NSNotification.Name jest zdefiniowany jako:

public struct Name : RawRepresentable, Equatable, Hashable, Comparable { 
    public init(_ rawValue: String) 
    public init(rawValue: String) 
} 

To jest trochę dziwne, ponieważ chciałbym oczekiwać, że będzie wyliczenia, a nie jakąś niestandardową struct z pozoru nie więcej korzyści.

Jest typealias w powiadamianiu o NSNotification.Name:

public typealias Name = NSNotification.Name 

Mylące jest to, że zarówno Powiadamianie i NSNotification istnieć w Swift

Więc w celu zdefiniowania swój własny powiadomienia zrobić somethine jak:

public class MyClass { 
    static let myNotification = Notification.Name("myNotification") 
} 

Wtedy to nazwać:

NotificationCenter.default().post(name: MyClass.myNotification, object: self) 
+2

Dobra odpowiedź. Kilka uwag: * To trochę dziwne, ponieważ spodziewałem się, że będzie to Enum * - Wyliczenie to zbiór * zamknięty *. Jeśli "Notification.Name" było wyliczeniem, nikt nie byłby w stanie zdefiniować nowych powiadomień. Używamy struktur dla typów typu "enum-like", które muszą umożliwiać dodawanie nowych członków. (Zobacz propozycję [swift-evolution] (https://github.com/apple/swift-evolution/blob/master/proposals/0033-import-objc-constants.md).) – rickster

+2

* Mylącą częścią jest to, że zarówno Powiadomienie i NSNotification istnieją w Swift * - "Notification" jest typem wartości (struct), dzięki czemu może korzystać z semantyki Swifta dla value (im) zmienności. Ogólnie rzecz biorąc, typy Fundacji upuszczają swoje "NS" w Swift 3, ale tam, gdzie istnieje jeden z nowych typów wartości fundamentowych, aby go zastąpić, stary typ referencyjny pozostaje w miejscu (zachowując nazwę "NS"), dzięki czemu można go nadal używać, gdy potrzebujesz semantyki referencyjnej lub jej podklasy. Zobacz [propozycję] (https://github.com/apple/swift-evolution/blob/master/proposals/0069-swift-mutability-for- foundation.md). – rickster

+0

Pozwól mi wyjaśnić: Oczekuję, że nazwy powiadomień będą wyliczone, podobnie jak błędy. Możesz zdefiniować własne wyliczenia błędów i dostosować je do ErrorType. – hexdreamer

256

Jest czystszy (chyba) sposób to osiągnąć

extension Notification.Name { 

    static let onSelectedSkin = Notification.Name("on-selected-skin") 
} 

I wtedy można go używać jak to

NotificationCenter.default.post(name: .onSelectedSkin, object: selectedSkin) 
+2

Używam powyższego kodu. To jest właściwość statyczna. –

+3

To jest świetny sposób, aby to zrobić. Upvote – crashoverride777

+3

Bardzo czysto, bardzo mi się podoba –

2

To jest po prostu odwołać

// 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) 
10

You można dodać niestandardowy inicjator do NSNotification.Name

extension NSNotification.Name { 
    enum Notifications: String { 
     case foo, bar 
    } 
    init(_ value: Notifications) { 
     self = NSNotification.Name(value.rawValue) 
    } 
} 

Zastosowanie:

NotificationCenter.default.post(name: Notification.Name(.foo), object: nil) 
+1

Małe litery" typ enum "i" init (_ type: type) "dla Swift 3.0.2 – Jalakoo

+0

@Jalakoo Only "przypadek" w wyliczeniu powinien być pisany małymi literami, a nie sam enum. Nazwy typów są pisane wielkimi literami, a wyliczenia są typami. – manmal

10

Prostszy sposób:

let name:NSNotification.Name = NSNotification.Name("notificationName") 
NotificationCenter.default.post(name: name, object: nil) 
3
NSNotification.Name(rawValue: "myNotificationName") 
3

Zrobiłem własną implementację miksowania rzeczy tam i tam i uważam to za najwygodniejsze. Dzielenie na który każdy że może być zainteresowany:

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) 
    } 
} 
1

Zaletą korzystania teksty stałe jest to, że możemy uzyskać kompilator, by sprawdzić, czy nazwa jest prawidłowa. Zmniejsza potencjalne problemy i ułatwia refaktoryzację.

Dla tych, którzy lubią za pomocą teksty stałe zamiast cudzysłowami w nazwach powiadomień, kod ten załatwia sprawę:

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) 
    } 
} 

Wtedy można go używać tak:

NotificationCenter.default.post(.somethingHappened) 

choć niezwiązany do pytanie, to samo można zrobić z sekwencjami scenariusza, aby uniknąć pisania cytowanych ciągów znaków:

enum StoryboardSegue: String { 
    case toHere 
    case toThere 
    case unwindToX 
} 

extension UIViewController { 
    func perform(segue: StoryboardSegue) { 
     performSegue(withIdentifier: segue.rawValue, sender: self) 
    } 
} 

Następnie na kontrolerze widoku, nazywają to lubią:

perform(segue: .unwindToX) 
0

jeśli używasz niestandardowych powiadomień String-tylko, że nie ma żadnych powodów, by przedłużyć klas ale String

extension String { 
     var notificationName : Notification.Name{ 
      return Notification.Name.init(self) 
     } 
    } 
Powiązane problemy