Reputation: 7510
I would like to create a couple protocols to have a more type-safe friendly Notification
interface.
The idea is to have a single type which from it, can be retrieved the notifications name, user info type (which will be the only entry of the dict), and a delegate for simplifying the observed response with the user info as a parameter.
Here are two protocols to help with building this interface.
protocol StructuredNotificationIdentifier {
associatedtype Delegate: StructuredNotificationUserInfoType
static var notification: Notification.Name { get }
}
protocol StructuredNotificationUserInfoType {
associatedtype UserInfoType
}
Here is an implementation of a notification with its name, user info type, and protocol.
protocol SomethingDidHappenDelegate: StructuredNotificationUserInfoType where UserInfoType == String {
func somethingDidHappen(_ value: UserInfoType)
}
enum SomethingDidHappenNotification: StructuredNotificationIdentifier {
typealias Delegate = SomethingDidHappenDelegate
static var notification: Notification.Name { Notification.Name("SomethingDidHappenNotification") }
}
And here is one more example of how the interface becomes simplified.
extension NotificationCenter {
func post<T: StructuredNotificationIdentifier>(identifier: T, userInfo: T.Delegate.UserInfoType) {
post(name: type(of: identifier).notification, object: nil, userInfo: ["info": userInfo])
}
}
Now, my error happens on the enum
declaration.
Type 'SomethingDidHappenNotification' does not conform to protocol 'StructuredNotificationIdentifier'
The problem as I understand it is coming from the StructuredNotificationIdentifier.Delegate
requiring conformance of StructuredNotificationUserInfoType
which also needs a defined associatedtype
. The part that I'm confused about is why this is not resolved with the SomethingDidHappenDelegate
declaration?
I understand I can set the user info type in multiple places, however since this is a pattern I'll be using often, I wanted the least amount of redundant code needed for the setup.
Why am I getting this error and is there an elegant way to resolve it?
Upvotes: 1
Views: 214
Reputation: 257749
The following makes your code compilable
enum SomethingDidHappenNotification<D: SomethingDidHappenDelegate>: StructuredNotificationIdentifier {
typealias Delegate = D
static var notification: Notification.Name { Notification.Name("SomethingDidHappenNotification") }
}
Upvotes: 1
Reputation: 271735
Protocols don't conform to protocols, so although it seems like
typealias Delegate = SomethingDidHappenDelegate
satisfies the Delegate
associated type requirement of StructuredNotificationIdentifier
, it doesn't, because Delegate
must conform to StructuredNotificationUserInfoType
. And SomethingDidHappenDelegate
, being a protocol, does not conform to any protocols.
I tried to come up with a workaround, and this is what I've got:
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])
}
}
I moved UserInfoType
into StructuredNotificationIdentifier
as well and deleted the constraint on Delegate
, because I don't think it is possible to access T.Delegate.UserInfoType
when Delegate
is a protocol. The error message I got when I tried to do that was pretty clear:
Associated type 'UserInfoType' can only be used with a concrete type or generic parameter base
Upvotes: 1