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

时间:2016-06-18 17:28:32

标签: swift nsnotificationcenter nsnotifications nsnotification swift3

在Objective-C中,自定义通知只是一个普通的NSString,但在WWDC版本的Swift 3中它并不是显而易见的。

13 个答案:

答案 0 :(得分:341)

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

extension Notification.Name {

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

然后你可以像这样使用它

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

答案 1 :(得分:35)

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,而不是一些看似没有更多好处的自定义结构。

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

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)

答案 2 :(得分:27)

你也可以使用这个协议

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的实施发生变化时,您才需要修改协议。

答案 3 :(得分:13)

更简单的方法:

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

答案 4 :(得分:10)

您可以向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)

答案 5 :(得分:6)

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

extension Notification.Name {
    static var notificationName: Notification.Name {
        return .init("notificationName")
    }
}

这将使您轻松发布和订阅通知。

NotificationCenter.default.post(Notification(name: .notificationName))

希望这会对您有所帮助。

答案 6 :(得分:4)

我做了自己的实现,从那里和那里混合东西,并发现这是最方便的。分享可能感兴趣的人:

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

答案 7 :(得分:3)

NSNotification.Name(rawValue: "myNotificationName")

答案 8 :(得分: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)

答案 9 :(得分: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)

虽然与问题无关,但故事板segues也可以这样做,以避免输入引用的字符串:

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

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

然后,在您的视图控制器上,将其命名为:

perform(segue: .unwindToX)

答案 10 :(得分:0)

如果您使用纯字符串自定义通知,则没有理由扩展任何类,但String

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

答案 11 :(得分:0)

@ CesarVarela的答案很好,但为了使代码更清洁,您可以执行以下操作:

extension Notification.Name {
    typealias Name = Notification.Name

    static let onSelectedSkin = Name("on-selected-skin")
    static let onFoo = Name("on-foo")
}

答案 12 :(得分:0)

如果您希望它在同时使用Objective-C和Swift的项目中正常工作,我发现在Objective-C中创建通知会更容易。

创建.m / .h文件:

//CustomNotifications.m
#import "CustomNotifications.h"

// Add their string values here
const NSNotificationName yourNotificationName = @"your_notification_as_string";
MyProject-Bridging-Header.h

在您的#import "CustomNotifications.h" (以您的项目命名)中,将其公开给Swift。

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(yourMethod:) name:yourNotificationName:nil];

像这样在Objective-C中使用通知:

NotificationCenter.default.addObserver(self, selector: #selector(yourMethod(sender:)), name: .yourNotificationName, object: nil)

在Swift(5)中是这样的:

SELECT *
FROM event
WHERE body->"$.item.id" = 651;