В Objective-C пользовательское уведомление представляет собой просто NSString, но это не очевидно в WWDC версии Swift 3 именно так, как должно быть.Как создавать пользовательские уведомления в Swift 3?
ответ
Вы также можете использовать протокол для этого
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
.
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)
Хороший ответ. Некоторые комментарии: * Это довольно странно, так как я ожидаю, что это будет Enum * - Перечисление - это * закрытый * набор. Если 'Notification.Name' было перечислением, никто не смог бы определить новые уведомления. Мы используем structs для типов, подобных другим типам, которые должны позволять добавлять новые члены. (См. [Предложение быстрой эволюции] (https://github.com/apple/swift-evolution/blob/master/proposals/0033-import-objc-constants.md). – rickster
* Запутанная часть состоит в том, что оба Уведомление и 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
Позвольте пояснить: я ожидаю, что имена уведомлений будут перечислены, например, Ошибки. Вы можете определить свои собственные перечисления ошибок и привести их в соответствие с ErrorType. – hexdreamer
Существует уборщик (я думаю) способ достичь его
extension Notification.Name {
static let onSelectedSkin = Notification.Name("on-selected-skin")
}
И тогда вы можете использовать его как этот
NotificationCenter.default.post(name: .onSelectedSkin, object: selectedSkin)
Я использую код выше. Это статическое свойство. –
Это потрясающий способ сделать это. Upvote – crashoverride777
Очень чистый, мне это нравится –
Это просто ссылка
// 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)
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)
более простой способ:
let name:NSNotification.Name = NSNotification.Name("notificationName")
NotificationCenter.default.post(name: name, object: nil)
NSNotification.Name(rawValue: "myNotificationName")
Я сделал свою собственную реализацию, перемещая вещи оттуда и там, и считаю это наиболее удобным. Совместное использование для тех, кто любой, что может быть интересно:
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)
}
}
Преимущество использования перечислений в том, что мы получаем компилятор, чтобы проверить, что имя правильно. Уменьшает потенциальные проблемы и упрощает рефакторинг.
Для тех, кто хотел с помощью перечислений вместо кавычек для имен уведомлений, этот код делает трюк:
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)
, если использовать строковые только пользовательских уведомлений, нет никаких причин, чтобы продлить любые классы, но String
extension String {
var notificationName : Notification.Name{
return Notification.Name.init(self)
}
}
Именно так я и думал, что он должен работать - уведомления должны быть перечислениями. Спасибо за трюк! – hexdreamer
Нет проблем! Я отредактировал код, чтобы включить конформацию расширения в «NotificationName», поэтому свойство «name» добавляется только к перечислениям, которые соответствуют протоколу. –
Строго эквивалентная, но более логичная ИМО, вы можете определить расширение для NotificationName (вместо RawRepresentable) следующим образом: 'extension NotificationName, где Self: RawRepresentable, Self.RawValue == String {' – jlj