如何在Swift 3中创建自定义通知?

hex*_*mer 110 nsnotifications nsnotification nsnotificationcenter swift swift3

在Objective-C中,自定义通知只是一个简单的NSString,但在WWDC版本的Swift 3中它并不明显.

Ces*_*ela 369

有一种更清洁(我认为)的方式来实现它

extension Notification.Name {

    static let onSelectedSkin = Notification.Name("on-selected-skin")
}
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用它

NotificationCenter.default.post(name: .onSelectedSkin, object: selectedSkin)
Run Code Online (Sandbox Code Playgroud)

  • `extension NSNotification.Name`而不是`extension Notification.Name`.否则Swift 3对''Notification'的投诉对于这种情况下的类型查找是不明确的 (10认同)
  • 值得注意的是,这是Apple在WWDC 2016 Session 207中建议的方法https://developer.apple.com/videos/play/wwdc2016/207/ (10认同)
  • 你得到了我在字符串中输入拼写错误的upvote,从而证明了输入通知名称的价值:P (9认同)
  • 这是一个很棒的方法.给予好评 (4认同)
  • 很干净,我很喜欢 (3认同)
  • @lluisgh没有收到你提到的任何错误. (3认同)
  • 我正在使用上面的代码.这是一个静态属性. (2认同)
  • 很好,虽然我猜字符串名称有冗余值的风险。 (2认同)

hex*_*mer 36

Notification.post定义为:

public func post(name aName: NSNotification.Name, object anObject: AnyObject?)
Run Code Online (Sandbox Code Playgroud)

在Objective-C中,通知名称是一个普通的NSString.在Swift中,它被定义为NSNotification.Name.

NSNotification.Name定义为:

public struct Name : RawRepresentable, Equatable, Hashable, Comparable {
    public init(_ rawValue: String)
    public init(rawValue: String)
}
Run Code Online (Sandbox Code Playgroud)

这有点奇怪,因为我希望它是一个Enum,而不是一些看似没有更多好处的自定义结构.

NSNotification.Name的通知中有一个typealias:

public typealias Name = NSNotification.Name
Run Code Online (Sandbox Code Playgroud)

令人困惑的部分是Swift中存在Notification和NSNotification

因此,为了定义您自己的自定义通知,请执行以下操作:

public class MyClass {
    static let myNotification = Notification.Name("myNotification")
}
Run Code Online (Sandbox Code Playgroud)

然后叫它:

NotificationCenter.default().post(name: MyClass.myNotification, object: self)
Run Code Online (Sandbox Code Playgroud)

  • 好答案.一些评论:*这有点奇怪,因为我希望它是一个枚举* - 枚举是一个*封闭*集.如果`Notification.Name`是枚举,则没有人能够定义新通知.我们将结构用于需要允许添加新成员的其他枚举类型.(参见[swift-evolution proposal](https://github.com/apple/swift-evolution/blob/master/proposals/0033-import-objc-constants.md).) (3认同)
  • *令人困惑的部分是Swift*中存在Notification和NSNotification - "Notification"是一种值类型(结构),因此它可以从Swift的值(im)可变性语义中受益.一般来说,基础类型正在Swift 3中删除它们的"NS",但是当存在一个新的基础值类型以取代它时,旧的引用类型会保留(保留"NS"名称),以便您仍然可以使用它你需要引用语义或子类化它.参见[提案](https://github.com/apple/swift-evolution/blob/master/proposals/0069-swift-mutability-for-foundation.md). (2认同)
  • 您可能是正确的,因为它应该以小写字母开头。 (2认同)

hal*_*l_g 31

您也可以使用协议

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

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

然后将通知名称定义为enum您想要的任何位置.例如:

class MyClass {
    enum Notifications: String, NotificationName {
        case myNotification
    }
}
Run Code Online (Sandbox Code Playgroud)

并使用它

NotificationCenter.default.post(name: Notifications.myNotification.name, object: nil)
Run Code Online (Sandbox Code Playgroud)

通过这种方式,通知名称将与基金会分离Notification.Name.并且您只需要修改您的协议,以防Notification.Name更改实施.

  • 严格等效但更符合逻辑的IMO,您可以在NotificationName(而不是RawRepresentable)上定义扩展,如下所示: `extension notificationName where Self: RawRepresentable, Self.RawValue == String {` (2认同)

Zol*_*adi 13

更简单的方法:

let name:NSNotification.Name = NSNotification.Name("notificationName")
NotificationCenter.default.post(name: name, object: nil)
Run Code Online (Sandbox Code Playgroud)


efr*_*dze 10

您可以向NSNotification.Name添加自定义初始值设定项

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

用法:

NotificationCenter.default.post(name: Notification.Name(.foo), object: nil)
Run Code Online (Sandbox Code Playgroud)


小智 8

我可能会建议另一个与@CesarVarela建议的选项类似的选项。

extension Notification.Name {
    static var notificationName: Notification.Name {
        return .init("notificationName")
    }
}
Run Code Online (Sandbox Code Playgroud)

这样您就可以轻松发布和订阅通知。

NotificationCenter.default.post(Notification(name: .notificationName))
Run Code Online (Sandbox Code Playgroud)

希望这会帮助你。