你如何在Swift 3中创build自定义通知?
在Objective-C中,自定义通知只是一个普通的NSString,但在Swift 3的WWDC版本中它并不明显。
你也可以使用这个协议
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)
这样通知名称将从Foundation Notification.Name
分离出来。 如果Notification.Name
的实现更改,则只需修改协议即可。
有一种更清洁(我认为)的方式来实现它
extension Notification.Name { static let onSelectedSkin = Notification.Name("on-sekected-skin") }
然后你可以像这样使用它
NotificationCenter.default.post(name: .onSelectedSkin, object: selectedSkin)
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) }
这是奇怪的,因为我希望它是一个枚举,而不是一些看似没有更多好处的自定义结构。
在NSNotification的通知中有一个typealias.Name:
public typealias Name = NSNotification.Name
令人困惑的是Swift中存在Notification和NSNotification
因此,为了定义自己的自定义通知,请执行以下操作:
public class MyClass { static let myNotification = Notification.Name("myNotification") }
然后调用它:
NotificationCenter.default().post(name: MyClass.myNotification, object: self)
更简单的方法:
let name:NSNotification.Name = NSNotification.Name("notificationName") NotificationCenter.default.post(name: name, object: nil)
您可以将自定义初始值设定项添加到NSNotification.Name
extension NSNotification.Name { enum Type: String { case foo, bar } init(_ type: Type) { self = NSNotification.Name(type.rawValue) } }
用法:
NotificationCenter.default.post(name: Notification.Name(.foo), object: nil)
NSNotification.Name(rawValue: "myNotificationName")
这只是参考
// 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)
我做了我自己的实现,从那里和那里混合的东西,并认为这是最方便的。 分享谁可能感兴趣的人:
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) } }
使用枚举的优点是我们让编译器检查名称是否正确。 减less潜在的问题,并使重构更容易。
对于那些喜欢使用枚举而不是引用string来通知名称的人来说,这段代码可以做到这一点:
enum MyNotification: String { case somethingHappened case somethingElseHappened case anotherNotification case oneMore } extension NotificationCenter { func add(observer: Any, selector: Selector, notification: CheckoutNotification, 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)
虽然与这个问题无关,但是可以使用storyboard segues来完成,以避免键入带引号的string:
enum StoryboardSegue: String { case toHere case toThere case unwindToX } extension UIViewController { func perform(segue: StoryboardSegue) { performSegue(withIdentifier: segue.rawValue, sender: self) } }
然后,在你的视图控制器上,像这样调用它:
perform(segue: .unwindToX)