1

我想创建几个协议来拥有更类型安全的友好Notification界面。

这个想法是有一个单一的类型,可以从中检索通知名称、用户信息类型(这将是 dict 的唯一条目)和一个委托,用于简化以用户信息作为参数观察到的响应。

这里有两个协议可以帮助构建这个接口。

protocol StructuredNotificationIdentifier {
    associatedtype Delegate: StructuredNotificationUserInfoType
    static var notification: Notification.Name { get }
}

protocol StructuredNotificationUserInfoType {
    associatedtype UserInfoType
}

这是一个通知的实现,它的名称、用户信息类型和协议。

protocol SomethingDidHappenDelegate: StructuredNotificationUserInfoType where UserInfoType == String {
    func somethingDidHappen(_ value: UserInfoType)
}

enum SomethingDidHappenNotification: StructuredNotificationIdentifier {
    typealias Delegate = SomethingDidHappenDelegate
    static var notification: Notification.Name { Notification.Name("SomethingDidHappenNotification") }
}

这是界面如何简化的另一个示例。

extension NotificationCenter {
    func post<T: StructuredNotificationIdentifier>(identifier: T, userInfo: T.Delegate.UserInfoType) {
        post(name: type(of: identifier).notification, object: nil, userInfo: ["info": userInfo])
    }
}

现在,我的错误发生在enum声明中。

类型“SomethingDidHappenNotification”不符合协议“StructuredNotificationIdentifier”

据我了解,问题来自于StructuredNotificationIdentifier.Delegate要求的一致性StructuredNotificationUserInfoType,也需要定义associatedtype. 我感到困惑的部分是为什么SomethingDidHappenDelegate声明没有解决这个问题?

我知道我可以在多个地方设置用户信息类型,但是由于这是我经常使用的模式,我希望设置所需的冗余代码最少。

为什么我会收到这个错误,有没有一种优雅的方法来解决它?

4

2 回答 2

1

协议不符合协议,所以虽然看起来像

typealias Delegate = SomethingDidHappenDelegate

满足 的Delegate关联类型要求StructuredNotificationIdentifier,它不满足,因为Delegate必须符合StructuredNotificationUserInfoType. 并且SomethingDidHappenDelegate,作为协议,不符合任何协议。

我试图想出一个解决方法,这就是我所拥有的:

protocol StructuredNotificationIdentifier {
    associatedtype Delegate
    associatedtype UserInfoType
    static var notification: Notification.Name { get }
}

protocol SomethingDidHappenDelegate {
    func somethingDidHappen(_ value: String)
}

enum SomethingDidHappenNotification: StructuredNotificationIdentifier {
    typealias Delegate = SomethingDidHappenDelegate
    typealias UserInfoType = String
    static var notification: Notification.Name { Notification.Name("SomethingDidHappenNotification") }
}

extension NotificationCenter {
    func post<T: StructuredNotificationIdentifier>(identifier: T, userInfo: T.UserInfoType) {
        post(name: type(of: identifier).notification, object: nil, userInfo: ["info": userInfo])
    }
}

我也搬进UserInfoTypeStructuredNotificationIdentifier并删除了对 的约束Delegate,因为我认为无法访问T.Delegate.UserInfoTypewhenDelegate是协议。当我尝试这样做时收到的错误消息非常清楚:

关联类型“UserInfoType”只能与具体类型或泛型参数库一起使用

于 2020-06-14T08:17:46.997 回答
1

以下使您的代码可编译

enum SomethingDidHappenNotification<D: SomethingDidHappenDelegate>: StructuredNotificationIdentifier {
    typealias Delegate = D
    static var notification: Notification.Name { Notification.Name("SomethingDidHappenNotification") }
}
于 2020-06-14T08:19:52.703 回答