无法使用Generic payload
对象创建NSNotification的子类。获取运行时错误或编译错误(请参阅下面的代码中的注释)。甚至可以使用Swift 2.1吗?任何想法都赞赏。谢谢!
运行时错误,因为NSNotification是抽象类(类集群) 编译错误因为应该使用指定的初始化程序。
public class Notification<T: Any>: NSNotification {
private var _name: String
private var _object: AnyObject?
private var _payload: T?
public override var name: String {
return _name
}
public override var object: AnyObject? {
return _object
}
public var payload: T? {
return _payload
}
/// Always nil. Use payload
public override var userInfo: [NSObject : AnyObject]? {
return nil
}
/// Change to false to "swap" implementation
#if true
init(name: String, object: AnyObject? = nil, payload: T? = nil) {
_name = name
_object = object
_payload = payload
/*
Runtime error:
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason:
'*** initialization method -initWithName:object:userInfo:
cannot be sent to an abstract object of class
_TtGC14__lldb_expr_1612NotificationSS_:
Create a concrete instance!'
*/
super.init(name: name, object: object, userInfo: nil)
}
#else
convenience init(name: String, object: AnyObject? = nil, payload: T? = nil) {
self.init()
_name = name
_object = object
_payload = payload
}
init() {
/// compiler error:
/// must call a designated initializer of the superclass
/// But using designated initializer cause runtime error listed above.
super.init()
}
#endif
}
let n = Notification<String>(name: "xyz", payload: "Hello")
答案 0 :(得分:8)
From the docs,强调我的:
除了通知名称,对象和字典之外,您还可以将
NSNotification
子类化为包含信息。这些额外的数据必须在通知者和观察者之间达成一致。
NSNotification
是一个没有实例变量的类集群。因此,您必须继承NSNotification
并覆盖原始方法name
,object
和userInfo
。您可以选择任何您喜欢的指定初始值设定项,但请确保初始值设定项不会调用[super init]
。NSNotification
并非意图直接实例化,其init
方法会引发异常。
现在没有办法从Swift代码中继承NSNotification
,因为Swift没有&#34;未初始化的类&#34;并要求所有子类调用他们的超类init
(在这种情况下,这是错误的做法)。
您必须在Objective-C中编写子类并将其桥接到您的Swift代码中。
不幸的是,即使您可以声明您的Objective-C类是通用的,该信息也会在桥接过程中丢失。 From the docs:
除了这些Foundation集合类之外,Swift还忽略了Objective-C轻量级泛型。使用轻量级泛型的任何其他类型都会导入到Swift中,就好像它们是未参数化的一样。
:(
答案 1 :(得分:0)
我在没有子类化的情况下解决了原始问题。
档案 GenericNotification.swift :
private let genericNotificationPayloadKey = "com.mc.notification-payload"
class GenericNotification<T: Any> {
let payload: T
let name: NSNotification.Name
let object: Any?
init(name: NSNotification.Name, object: Any? = nil, payload: T) {
self.name = name
self.object = object
self.payload = payload
}
init?(notification: Notification) {
guard let payload = notification.userInfo?[genericNotificationPayloadKey] as? T else {
return nil
}
self.payload = payload
name = notification.name
object = notification.object
}
}
extension GenericNotification {
var notification: Notification {
return Notification(name: name, object: object, userInfo: [genericNotificationPayloadKey: payload])
}
static func observe(name: NSNotification.Name,
object: Any? = nil,
queue: OperationQueue = .main,
handler: @escaping (T) -> Void) -> NotificationObserver {
return NotificationObserver(name: name, object: object, queue: queue) {
if let notification = GenericNotification(notification: $0) {
handler(notification.payload)
}
}
}
func post(center: NotificationCenter = NotificationCenter.default) {
center.post(notification)
}
}
文件 NotificationObserver.swift :
class NotificationObserver: NSObject {
typealias Handler = ((Foundation.Notification) -> Void)
private var notificationObserver: NSObjectProtocol!
var notificationHandler: Handler?
private let notificationName: NSNotification.Name
private let notificationObject: Any?
init(name: NSNotification.Name, object: Any? = nil, queue: OperationQueue = .main, handler: Handler? = nil) {
notificationName = name
notificationObject = object
notificationHandler = handler
super.init()
notificationObserver = NotificationCenter.default.addObserver(forName: name, object: object, queue: queue) { [weak self] in
self?.handleNotification($0)
}
}
deinit {
NotificationCenter.default.removeObserver(notificationObserver, name: notificationName, object: notificationObject)
}
/// Calls block which was passed as *usingBlock* parameter.
/// Child classes may override to change default behaviour.
/// - parameter notification: Notification to handle.
func handleNotification(_ notification: Foundation.Notification) {
notificationHandler?(notification)
}
}
<强>用法强>:
// Send notification
let action = MyType.doSomething
GenericNotification(name: .myNotificationName, payload: action).post()
// Receive notification
private var notificationObservers: [NotificationObserver] = []
...
notificationObservers.append(GenericNotification<MyType>.observe(name: .myNotificationName) { instanceOfMyType in
// Got `instanceOfMyType` which is `MyType.doSomething`
})