ответ

18

Вы также можете использовать протокол для этого

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

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

А затем определить ваши имена уведомления как enum в любом месте вы хотите , Например:

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

и использовать его как

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

Таким образом, имена уведомления будут отделены от Фонда Notification.Name. И вам придется изменить свой протокол только в случае, если будет изменена реализация для Notification.Name.

+0

Именно так я и думал, что он должен работать - уведомления должны быть перечислениями. Спасибо за трюк! – hexdreamer

+0

Нет проблем! Я отредактировал код, чтобы включить конформацию расширения в «NotificationName», поэтому свойство «name» добавляется только к перечислениям, которые соответствуют протоколу. –

+0

Строго эквивалентная, но более логичная ИМО, вы можете определить расширение для NotificationName (вместо RawRepresentable) следующим образом: 'extension NotificationName, где Self: RawRepresentable, Self.RawValue == String {' – jlj

31

Notification.post определяется как:

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

В Objective-C, имя уведомления является простым NSString. В Swift это определяется как NSNotification.Name.

NSNotification.Name определяется как:

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

Это немного странно, так как я ожидал бы быть Enum, а не какой-то пользовательский-структуру, казалось бы, не больше пользы.

Существует typealias в оповещении для NSNotification.Name:

public typealias Name = NSNotification.Name 

Запутанной часть, что оба уведомления и NSNotification существуют в Swift

Так что для того, чтобы определить свое собственное уведомление, делать somethine как:

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

Тогда назвать:

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

Хороший ответ. Некоторые комментарии: * Это довольно странно, так как я ожидаю, что это будет Enum * - Перечисление - это * закрытый * набор. Если 'Notification.Name' было перечислением, никто не смог бы определить новые уведомления. Мы используем structs для типов, подобных другим типам, которые должны позволять добавлять новые члены. (См. [Предложение быстрой эволюции] (https://github.com/apple/swift-evolution/blob/master/proposals/0033-import-objc-constants.md). – rickster

+2

* Запутанная часть состоит в том, что оба Уведомление и NSNotification существуют в Swift * - «Уведомление» - это тип значения (структура), так что он может извлечь выгоду из семантики Swift для изменчивости value (im). Как правило, типы Foundation отбрасывают свои «NS» в Swift 3, но там, где существует один из новых типов базовых значений, чтобы заменить его, старый ссылочный тип хранится вокруг (сохраняя имя «NS»), чтобы вы все еще могли использовать его, когда вам нужна эталонная семантика или подкласс. См. [Предложение] (https://github.com/apple/swift-evolution/blob/master/proposals/0069-swift-mutability-for-foundation.md). – rickster

+0

Позвольте пояснить: я ожидаю, что имена уведомлений будут перечислены, например, Ошибки. Вы можете определить свои собственные перечисления ошибок и привести их в соответствие с ErrorType. – hexdreamer

256

Существует уборщик (я думаю) способ достичь его

extension Notification.Name { 

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

И тогда вы можете использовать его как этот

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

Я использую код выше. Это статическое свойство. –

+3

Это потрясающий способ сделать это. Upvote – crashoverride777

+3

Очень чистый, мне это нравится –

2

Это просто ссылка

// 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 может добавить пользовательский инициализатор в NSNotification.Name

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

Использование:

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

Нижний регистр 'enum type' и 'init (_ type: type)' для Swift 3.0.2 – Jalakoo

+0

@Jalakoo Only '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ', а не перечисление. Имена типов в верхнем регистре, а перечисления - это типы. – manmal

10

более простой способ:

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

Я сделал свою собственную реализацию, перемещая вещи оттуда и там, и считаю это наиболее удобным. Совместное использование для тех, кто любой, что может быть интересно:

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

Преимущество использования перечислений в том, что мы получаем компилятор, чтобы проверить, что имя правильно. Уменьшает потенциальные проблемы и упрощает рефакторинг.

Для тех, кто хотел с помощью перечислений вместо кавычек для имен уведомлений, этот код делает трюк:

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

Затем вы можете использовать его как это:

NotificationCenter.default.post(.somethingHappened) 

Хотя не связан с вопрос, то же самое можно сделать с помощью раскадровки, чтобы избежать наложения строк:

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

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

Затем на контроллере вида, называют это нравится:

perform(segue: .unwindToX) 
0

, если использовать строковые только пользовательских уведомлений, нет никаких причин, чтобы продлить любые классы, но String

extension String { 
     var notificationName : Notification.Name{ 
      return Notification.Name.init(self) 
     } 
    }