salman siddiqui
salman siddiqui

Reputation: 902

Function with Array of Generics as Parameter in Swift

I want to make a generic function which takes a generic array as a parameter. I have two classes Animal and Bird as well as two protocols Animals & Birds and my method parameter conforms to these two protocols but I am not able to add to the array.

protocol Birds {
    var canFly: Bool {get set}
}

protocol Animals {
    var name: String {get set}
    var legs: Int {get set}
}

class Animal: Animals {
    var name: String
    var legs: Int

    init(name: String, legs: Int) {
        self.name = name
        self.legs = legs
    }
}

class Bird: Birds {
    var canFly: Bool
    init(canFly: Bool) {
        self.canFly = canFly
    }
}

func myTestGenericMethod<T>(array: [T]) where T: Animals & Birds {
    for (index, _) in array.enumerated() {
        print("At last i am able to get both Animal and Bird")
    }
}

let cat = Animal(name: "cat", legs: 4)
let dog = Animal(name: "dog", legs: 4)
let crow = Bird(canFly: true)
myTestGenericMethod(array: [dog])

myTestGenericMethod(array: [cat, dog]) // Not Able to add this to array

Upvotes: 2

Views: 3839

Answers (2)

trungduc
trungduc

Reputation: 12154

When you write where T: Animals & Birds, T must be extended from Animals AND Birds

But cat and dog aren't extended from both Animals AND Birds. So this is problem.

As I understand, you want T have to be extended from Animals OR Birds. To do it, we must have a base protocol which both Animals and Birds are extended from. Change a little code and fix it.

@objc protocol Base {
}

protocol Birds : Base {
  var canFly: Bool {get set}
}

protocol Animals : Base {
  var name: String {get set}
  var legs: Int {get set}
}

class Animal: Animals {
  var name: String
  var legs: Int

  init(name: String, legs: Int) {
    self.name = name
    self.legs = legs
  }
}

class Bird: Birds {
    var canFly: Bool
    init(canFly: Bool) {
      self.canFly = canFly
    }
  }

func myTestGenericMethod<T: Base>(array: [T]) {
  for object in array {
    if object is Bird {
      let bird = object as! Bird
      print(bird.canFly)
    } else if object is Animal {
      let animal = object as! Animal
      print(animal.name)
    }
  }
}

let cat = Animal(name: "cat", legs: 4)
let dog = Animal(name: "dog", legs: 4)
let crow = Bird(canFly: true)
myTestGenericMethod(array: [crow, cat, dog] as! [Base])
myTestGenericMethod(array: [cat, dog])

Upvotes: 2

algrid
algrid

Reputation: 5954

In your code where T: Animals & Birds means that you require T to be an instance conforming to both protocols at the same time. But you don’t have a class conforming to both protocols. If you create one then you’ll be able to use its instances in your generic method.

Upvotes: 1

Related Questions