In Swift, How to Declare a Variable of a Specific Type That Conforms to One or More Protocols

In Swift, how can I declare a variable of a specific type that conforms to one or more protocols?

In Swift 4 it is now possible to declare a variable that is a subclass of a type and implements one or more protocols at the same time.

var myVariable: MyClass & MyProtocol & MySecondProtocol

To do an optional variable:

var myVariable: (MyClass & MyProtocol & MySecondProtocol)?

or as the parameter of a method:

func shakeEm(controls: [UIControl & Shakeable]) {}

Apple announced this at WWDC 2017 in Session 402: Whats new in Swift

Second, I want to talk about composing classes and protocols. So, here
I've introduced this shakable protocol for a UI element that can give
a little shake effect to draw attention to itself. And I've gone ahead
and extended some of the UIKit classes to actually provide this shake
functionality. And now I want to write something that seems simple. I
just want to write a function that takes a bunch of controls that are
shakable and shakes the ones that are enabled to draw attention to
them. What type can I write here in this array? It's actually
frustrating and tricky. So, I could try to use a UI control. But not
all UI controls are shakable in this game. I could try shakable, but
not all shakables are UI controls. And there's actually no good way to
represent this in Swift 3. Swift 4 introduces the notion of composing
a class with any number of protocols.

Variable of type that conforms to protocol

You need to work with generics (associatedtype in protocols)

protocol ViewModel {
var isActive: Bool { get }
}

struct TestViewModel: ViewModel {
var isActive = false
}

protocol View {
associatedtype V: ViewModel
var viewModel: V { get }
}

struct TestView: View {
var viewModel: TestViewModel
}

This should works, you are telling to the struct that viewModel should be some class that implements ViewModel protocol

Swift 5: how to specify a generic type conforming to protocol when declaring a variable

An associated type is used when you want your protocol to work with a variety of types, think a Container protocol that might have several methods all dealing with one contained type.

But your protocol is not that, it doesn't need to know any other types to specify the necessary behavior, so get rid of the associated type.

protocol Pipe {
func await() -> Void
func yield( to: Any, with listener: Selector ) -> Void
}

class Foo {
var imageSource: Pipe & Renderable
}

Variable that conforms to a protocol that has a generic function

Swift doesn't allow this.

Here's why: you don't know anything about the type of argument person.forward(_:) takes. There is no way to call it. MyProtocol essentially defines an open-ended set of independent types.

If you don't want to be able to call person.forward(_:), and you just want to be able to access the non-generic person.name property, then split your protocol into a base, non-generic protocol defining name, and a sub-protocol that adds the generic forward(_:) method.

protocol NamedThing {
var name: String {get set}
}

protocol MovableNamedThing: NamedThing {
associatedtype SpeedType
func forward(_: SpeedType)
}

class A: MovableNamedThing {
typealias SpeedType = Double
var name: String

init(name:String) {
self.name = name
}

func forward(_ s: Double) {
print("Moving \(s) km/h")
}
}

class B: MovableNamedThing {
typealias SpeedType = Int
var name: String

init(name:String) {
self.name = name
}

func forward(_ s: Int) {
print("Moving \(s) km/h")
}
}

let x: Bool = true
var person: NamedThing
if x {
person = A(name: "Robot")
} else {
person = B(name: "Human")
}


Related Topics



Leave a reply



Submit