Swift Array of Class Types that Each Conform to a Protocol and are Subclasses of Common Class

Viewed 4708

I have a method in Swift with a signature of the form:

func myMethod<T>(class: T.Type) where T: SomeClass & MyProtocol

I would like to have a variable that is an array of classes that are all subclasses of SomeClass and conform to MyProtocol.

It would look something like:

let classArray = [SubclassOfSomeClass.self, SubclassTwoOfSomeClass.self, SubclassThreeOfSomeClass.self]

Where each of SubclassOfSomeClass, SubclassTwoOfSomeClass and SubclassThreeOfSomeClass conform to MyProtocol

I would then like to call myMethod as follows:

classArray.forEach { classType in

    myMethod(class: classType)
}

I receive the compiler error "Generic parameter T could not be inferred". This makes sense to me as the type of classArray variable is inferred as [MyClass.Type].

My question is, can and how do I define the variable classArray such that the compiler knows that every type defined therein conforms to the protocol MyProtocol.

2 Answers

You can achieve that by having SomeClass conform to MyProtocol. Therefore every subclass would also have to conform to MyProtocol.

Then your method signature would be just:

func myMethod<T>(class: T.Type) where T: SomeClass

If that is not desired then you can change the type of myMethod to not be generic. I think swift is unable to type the array to have elements of (SomeClass & MyProtocol).Type. In your case you are not really using a generic object. You do have a specific type in mind and it is (SomeClass & MyProtocol).Type. Your code would look something like this:

protocol MyProtocol: class {

}

class SomeClass: NSObject {

}

class SubClass: SomeClass, MyProtocol {

}

class SubClass2: SomeClass, MyProtocol {

}

let classArray: [(SomeClass & MyProtocol).Type] = [SubClass.self, SubClass2.self]

func myMethod(class: (SomeClass & MyProtocol).Type) {

}

classArray.forEach {
    myMethod(class: $0)
}
protocol MyProtocol {
   var x: Int { get }
}

class MyClass: NSObject {
    var y: Int = 10
}

class SubClass1: MyClass, MyProtocol {
    private(set) var x: Int = 9
}

class SubClass2: MyClass {
}

class SubClass3: MyClass, MyProtocol {
    var x: Int { return 15 }
}

let items: [MyClass & MyProtocol] = [SubClass1(), SubClass3()]

func myMethod(_ item: MyClass & MyProtocol) {}

classArray.forEach { myMethod($0) }

So for now you can use just MyClass & MyProtocol

Related