I'd like to return a UIViewController
conforming to MyProtocol
from a method, so I'm using the method signature:
func myMethod<T where T : UIViewController, T : MyProtocol>() -> T {
First thing I don't understand: if myMethod
returns e.g. a MyViewController
which has to following signature, I have to force cast it:
class MyViewController: UIViewController, MyProtocol
I cannot simply return MyViewController()
but I need to cast it like this: return MyViewController() as! T
- why is this necessary?
And the second thing: how can I use this method somewhere? I cannot simply say
let x = myMethod() as? UIViewController
as I get the error
Generic parameter 'T' could not be inferred
How can I achieve something like this? If I cast it to MyViewController
it works, but I would like to avoid that of course.
EDIT: Example
class MyViewController : UIViewController, MyProtocol { } protocol MyProtocol { } func myMethod<T>() -> T where T : UIViewController, T : MyProtocol { return MyViewController() as! T // why is the cast necessary? }
ok, I do get one part, but why is the cast to T
necessary? MyViewController
is a subclass of UIViewController
and conforms to the protocol, so no cast should be necessary, right?
Generic code enables you to write flexible, reusable functions and types that can work with any type, subject to requirements that you define. You can write code that avoids duplication and expresses its intent in a clear, abstracted manner.
Generics and Any are often used for similar purposes, yet they behave very differently. In languages without generics, you typically use a combination of Any and runtime programming, whereas generics are statically checked at compile time.
func myMethod<T where T : UIViewController, T : MyProtocol>() -> T
This declaration says: There exists a function called myMethod
, such that myMethod
returns some specific T
where T
is a subtype of UIViewController
and also MyProtocol
. This does not say what type T
actually is, and it does not say that there is only one such myMethod
. There can be many if there are many type that are both subclasses of UIViewController
and conform to MyProtocol
. Every one of those types creates a new version of myMethod
(really a new solution to the assertion myMethod
makes, that such a function does exist).
This is not the same thing as:
func myMethod() -> UIViewController
That says: The function myMethod
returns any subtype of UIViewController
.
There is no way in Swift to express "any type that is a subclass of UIViewController and is a subtype of MyProtocol." You can only discuss a specific type that meets that criterial. Swift can't combine classes and protocols this way; it's just a current limitation of the language, not a deep design issue.
The specific versus any is the issue. There are many functions that satisfy your myMethod
declaration. Every T
you can plug in that conforms to the rules would be a candidate. So when you say myMethod()
, the compiler doesn't know which specific T
you mean.
(I was going to expand this answer to provide it in less type-theory, more "how do you do it in code" terms, but donnywals already has an excellent version of that.)
* To your edited question *
func myMethod<T>() -> T where T : UIViewController, T : MyProtocol { return MyViewController() as! T // why is the cast necessary? }
T
is a specific type decided by the caller. It is not "any type that conforms" it is "some specific, concrete type that conforms." Consider the case that you called:
let vc: SomeOtherViewController = myMethod()
In this case, T
is SomeOtherViewController
. MyViewController
is not that type, so what you're doing with the as!
cast is dangerous.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With