问题
Maybe it's a stupid question, but I couldn't find any solutions yet. So, my problem is, that is have an event emitter protocol with a function like this:
mutating func on(eventName:String, action:((Any?)->())) {
//..
}
And I want to use it to inform the listeners whenever an event is triggered with some information. Access token for the "login" event for example.
appSessionHadler.on("login") { (weak data: String?) in
//...
}
And than I get an error, that I cannot invoke "on" with that argument list of type. Of course it works with Any:
appSessionHadler.on("login") { (weak data: Any?) in
//...
}
Everything conforms to Any, so I'm a but confused. Can someone explain this, please!
I could solve this with a Generic protocol, but it still frustrates me that it does not works like this.
回答1:
You're making a promise the compiler can't keep. The on
function is free to call action
with any kind of data at all. But the function you passed only accepts String
. What is the system supposed to do if on
includes the following code (directly or indirectly):
action(1)
1
is not a String
, so type safety would be broken. The compiler can't let you do that.
Another way to think about this is that on
takes a function of type F
, and you are passing a supertype of F
rather than a subtype of F
. String
is a subtype of Any
. But function parameters work in the reverse order. (String)->Void
is a supertype of (Any)->Void
. So this is the same as passing a variable of type Any
to a function that requires String
. Formally we say that functions are contravariant in their parameters and covariant in their return values. You can read more on that in Type Variance in Swift.
As you suspect, generics are the right answer here. Any
is almost always the wrong tool. And Any?
is one of the hardest types to work with in Swift, so I'd definitely avoid that one at all costs. (Optional
is itself a subtype of Any
, and Swift has automatic promotion to Optional
, so it is very common when you have Any?
to start getting double Optionals and worse.)
来源:https://stackoverflow.com/questions/35697569/swift-closure-cannot-override-any