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
Uibutton Custom Font Vertical Alignment
Remove or Uninstall Library Previously Added: Cocoapods
Swift - Stored Values Order Is Completely Changed in Dictionary
Didregisterforremotenotificationswithdevicetoken Not Called in Ios8, But Didregister...Settings Is
Calling a Phone Number in Swift
Reason: No Suitable Image Found
Post Request with a Simple String in Body with Alamofire
Codesign Error: Provisioning Profile Cannot Be Found After Deleting Expired Profile
How to Import Own Classes from Your Own Project into a Playground
Sprite Kit & Playing Sound Leads to App Termination
How to See Saved Nsuserdefaults
Programmatically Align a Toolbar on Top of the Iphone Keyboard
Using Nsuserdefaults on Arrays
Issue Detecting Button Cellforrowat
How to Handle Background Audio Playing While iOS Device Is Locked or on Another Application