2

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
2
  • is it working for single object in array ? myTestGenericMethod(array: [dog]) ? Commented Dec 29, 2017 at 7:36
  • ya its woking if i use where T: Animals only. Commented Dec 29, 2017 at 7:37

2 Answers 2

2

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])
Sign up to request clarification or add additional context in comments.

11 Comments

Nice.!! but if i use Base Protocol then all properties from both protocols need to be added. Then here one problem come where Animal will not have can Flying property it will force to add Flying to Animal.
No, you dont need add anything to Base protocol. As you can see Base protocol is empty. It’s only used to check T is Bird OR Animal. It’s OR not AND :)
ok then how can i access properties from myTestGenericMethod array in loop like object.name or object.canFly ..??
I dont have a machine now to give you a piece of code but you can do it. Use a loop with array. With each object, check if type of this object is Birds, call fly. If type of this object is Animals, call name. Try it. If you can’t do it, tell me.
I tried i am not getting it if you get time please add your sample working code here.
|
1

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.

1 Comment

myTestGenericMethod(array: [cat, crow]) either of one is taking if i add like this its giving (cannot convert value of type [Any] to expected argument type [_])

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.