I have an abstract class
defined this way:
class BaseCoordinator<ResultType>
Other classes inherit from this one eg.
final class AppCoordinator: BaseCoordinator<Void>
final class AuthFlowCoordinator: BaseCoordinator<AuthFlowCoordinationResult>
final class MainFlowCoordinator: BaseCoordinator<Void>
Now I want to create a factory method. I guess it's sugnature should look like:
func makeCoordinator<T>() -> BaseCoordinator<T>
But, of course, I get error like this one:
Cannot convert return expression of type 'AppCoordinator' to return type 'BaseCoordinator<T>'
What Xcode suggests me is to add as! BaseCoordinator<T>
as! BaseCoordinator<T>
, but I hate this force downcasting (and returning ?
isn't satisfying me either, as I'm 100% sure I'll have a correct default object), as I want assurance that at least a default Coordinator
will be returned.
It feels like I'm missing something, but I really have no clue what is it. Is it actually possible to make such factory method, or is Swift generics limited?
T
must have a predefined type at compile time. Therefore you cannot choose T
using the implementation of makeCoordinator()
by returning different coordinators with different ResultType
s.
In this case, the caller can choose which value he wants to assign to T
, potentially breaking the function. For example the following two calls would be perfectly valid:
let coordinator: BaseCoordinator<Void> = makeCoordinator()
let coordinator: BaseCoordinator<[Int: [String]]> = makeCoordinator()
It would not make sense to use [Int: [String]]
as a generic type but it is still possible. Depending on the generic type you choose at the function call, the cast may work or not, which is why a force cast will likely lead to a crash.
An optional cast, as suggested by Tom E would fix the potential crash but it would still not resolve this problem.
Therefore you cannot use a factory pattern for this without erasing ResultType
to Any
using a wrapper type, which would defeat the purpose of generics.
If you want type safety, you have to create a factory method for each subclass of BaseCoordinator
you want to instantiate or just call their initializers manually.
You might want to try as?
instead of as!
. The former yields an optional, ie the result will be nil if the cast doesn't succeed. This way you have a safe cast without the need of forcing anything.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.