Please consider the following classes:
// Models:
class A {}
class B: A { }
// Parsers:
class AbstractParser<T> {}
class ParserB<T: B>: AbstractParser<T> {}
// Services:
class AbstractService<T> {
func parser() -> AbstractParser<T> {
fatalError("This method must be overridden")
}
}
class ServiceA<T: A>: AbstractService<T> {
}
class ServiceB<T: B>: ServiceA<T> {
private let _parser = ParserB()
override func parser() -> ParserB<B> {
return _parser
}
}
I'm getting an error Method doesn not override any method from it's superclasses
at overriden parser
function. I could easily fix this by changing
class ServiceB<T: B>: ServiceA<T>
to
class ServiceB<T: B>: ServiceA<B>
but this will break a solution from this question: A variable in generic class gets wrong type
Is there any workaround for this?
EDIT
Thanks, Kenneth Bruno, your approach works, but it again leads to another error with types.
I add class C
:
class C {
var item = B()
}
and a simple method to ServiceB
:
func doSomething() {
var entities = [T]()
let c = C()
entities.append(c.item)
}
This causes error: Cannot invoke 'append' method with an argument list of type '(B)'
. It seems the compiler can't understand that B
and T
are the same thing?
Also please note that I can't define var entities = [B]()
, as I need to pass this array to another function in AbstractService
method.
Just as in your other question you need to use the generic type instead of a specific type, then the method signatures will match to override the function.
class ServiceB<T: B>: ServiceA<T> {
private let _parser = ParserB<T>()
override func parser() -> ParserB<T> {
return _parser
}
}
From the question edit:
This causes error:
Cannot invoke 'append' method with an argument list of type '(B)'
. It seems the compiler can't understand thatB
andT
are the same thing?
Just to clarify things. In the edit code example <T: B>
and B
are not the same thing. B
is a regular type, while <T: B>
is a generic type, which may represent a B
type or any of it's subtypes.
Merging the question code with the code proposed by @Kenneth results in the following, which leads to a type error
class C {
var item = B()
}
class ServiceB<T: B>: ServiceA<T> {
private let _parser = ParserB<T>()
override func parser() -> ParserB<T> {
return _parser
}
func doSomething() {
var entities = [T]()
let c = C()
entities.append(c.item) // Error: Cannot invoke 'append' method with an argument list of type '(B)'
}
}
Now let's say in the future we add a new type D
, subtype of B
and instantiate a ServiceB<D>
. This would cause the function doSomething()
to try to append an instance of B
in an array of D
which is illegal, that's why the compiler raises an error.
With the code proposed in the comments by @Kenneth, the entities
array would be filled in the ServiceB<B>
case, but would always be empty in the ServiceB<D>
.
class D: B { }
class ServiceB<T: B>: ServiceA<T> {
...
func doSomething() {
var entities = [T]()
let c = C()
if let item = c.item as? T { entities.append(item) }
}
}
let service = ServiceB<B>()
service.doSomething() // Creates an array of B and append a single B instance on it
let serviceD = ServiceB<D>()
serviceD.doSomething() // Creates an array of D, c.item of type B can't be cast to D, the array will be empty
While my answer doesn't really solves your problem, I think it should put you one step closer to a solution.
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.