Generic classes and inheritance
I have a model object:
class Animal {
// ...
}
And subclasses:
class Dog: Animal {
// ...
}
class Cat: Animal {
// ...
}
Also I created a generic class
class AnimalController<T: Animal> {
var animal: T?
func feed(animal: T) {
let food = Food(T.self)
animal.feed(food)
}
}
This is the problem:
class MainViewController: UIViewController {
var controller: AnimalController<Animal>?
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
// I want control a dog
self.controller = AnimalController<Dog>() // Error
// I want control a cat
self.controller = AnimalController<Cat>() // Error
}
}
How can I create a generic class that is compatible with both dogs and cats? Thank!
UPDATED Hamish will give me a solution linking the other two posts.
I have a model object:
class Animal {
// ...
}
And subclasses:
class Dog: Animal {
// ...
}
class Cat: Animal {
// ...
}
Also I created a generic class
class AnimalController<T> {
var type: T
init(type: T) {
self.type = type
}
func feed() {
if type is Animal.Type {
let food = Food(type as! Animal.Type)
animal.feed(food)
}
}
}
Now it works:
class MainViewController: UIViewController {
var controller: AnimalController<Animal>?
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
// I want control a dog
self.controller = AnimalController<Dog>() // Works!
self.controller = AnimalController<Cat>() // Works!
}
}
source to share
This is similar to the case where inheritance should be used instead of generics.
class AnimalController {
// basic animal control tasks
}
class CatController: AnimalController {
// specialized controller just for cats
}
class DogController: AnimalController {
// ...
}
Then you could just write
class MainViewController: UIViewController {
var animalController: AnimalController
override func viewDidLoad() {
super.viewDidLoad()
// I want control a dog
self.controller = DogController()
// I want control a cat
self.controller = CatController()
}
}
Working with generics can lead to problems in this case, as the Swift compiler resolves generic types and replaces them with specific types (which is not possible unless you create an entire generic view controller, but it will work well with an interface builder)
source to share
In your example, there is no need to create a AnimalController
generic class. It can just have methods that work for Animals
, and they will work for Dog
as well as Cat
through inheritance.
class Animals {
// ...
}
class Dog: Animals {
// ...
}
class Cat: Animals {
// ...
}
class AnimalController {
// methods to control any kind of animals
var animal: Animals? // Will take both cats and dogs
func feed(animal: Animals) {
// Will take both cats and dogs
}
}
class MainViewController: UIViewController {
var controller: AnimalController?
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
// I want control a dog or a cat
self.controller = AnimalController()
let cat = Cat()
controller?.animal = cat
controller?.feed(animal: cat)
let dog = Dog()
controller?.animal = dog
controller?.feed(animal: dog)
}
}
(updated)
Even after your changes, I see no need for generics:
class Animal {
// ...
func feed(_ food: Food){
// feed the animal or maybe throw an error
// if subclasses must implement
}
}
class Dog: Animal {
// ...
override func feed(_ food: Food) {
// feed a cat
}
}
class Cat: Animal {
// ...
override func feed(_ food: Food) {
// feed a dog
}
}
class Food {
init(_ animalType: Animal.Type) {
// Make food
}
}
class AnimalController {
// methods to control any kind of animals
var animal: Animal? // Will take both cats and dogs
func feed(animal: Animal) {
// Will take both cats and dogs
let food = Food(type(of: animal))
animal.feed(food)
}
}
class MainViewController: UIViewController {
var controller: AnimalController?
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
// I want control a dog or a cat
self.controller = AnimalController()
let cat = Cat()
controller?.animal = cat
controller?.feed(animal: cat)
let dog = Dog()
controller?.animal = dog
controller?.feed(animal: dog)
}
}
source to share