Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift: Array property with elements conforming to a class and multiple protocols simultaneously

In Objective-C there is a way to declare a variable conforming to a class and a set of protocols like this:

BaseClass<Protocol1, Protocol2> *variable = ...

In Swift I would like to declare an array (actually as a property of a class) with elements of a type defined by this pattern.

In this question there is a solution for describing the type of a standalone property by making the class generic and constraining the type accordingly. In order to instantiate such a class it would be necessary to specify the exact type. This is not a problem for a standalone property, but in an array there should be possible to store elements with different exact types.

Is there a way how to express this in Swift?

like image 752
Lukas Kubanek Avatar asked Jan 19 '15 14:01

Lukas Kubanek


2 Answers

I just came across this old question of mine and because the Swift language evolved since accepting the partial answer I decided to post another answer which actually solves the problem I originally asked.

From version 4, Swift supports protocol composition using the & sign which can also be composed with one class type.

class BaseClass {}
protocol Protocol1 {}
protocol Protocol2 {}

class ConformingClass1: BaseClass, Protocol1, Protocol2 {}
class ConformingClass2: BaseClass, Protocol1, Protocol2 {}

// It works for a variable holding a single object.
let object: BaseClass & Protocol1 & Protocol2 = ConformingClass1()

// And it also works for a variable holding an array of objects.
let array: [BaseClass & Protocol1 & Protocol2] = [ConformingClass1(), ConformingClass2()]
like image 147
Lukas Kubanek Avatar answered Oct 16 '22 13:10

Lukas Kubanek


In the case, that you want to store only objects conforming to your protocols, you can make another protocol which inherits the others, e.g.

protocol A { }
protocol B { }
protocol C : A, B { }

Now you can create the corresponding array

var objects : [ C ]

You can store any object, as long as it conforms to the C-protocol and thus to A and B as well:

class Foo : X { }
class Bar : X { }

objects.append(Foo()) // [ Foo ]
objects.append(Bar()) // [ Foo, Bar ]

The technique behind is Protocol Inheritance.

Update IMO this is not feasible with the Array of Swift. Because, you can either store a type inherited from a base class or AnyObject, which does not satisfy your constraints. But you could possibly create a wrapper which checks the object you try to append to your array and rejects it if it does not fit the constraints.

like image 45
Sebastian Dressler Avatar answered Oct 16 '22 12:10

Sebastian Dressler