Associated Types in Swift one of the best way to define the protocols that can be reused among multiple different types. It works very closely together with protocols. The actual type to use for that associated type can’t specified until the protocol adopted. It is specified with the associatedtype keyword.
The protocol can only used as a generic by associated type. It prevents writing duplicate code by making it easier to define a common interface for multiple scenarios. From that way, the same logic you can be reused for multiple different types and allowed to write and test logic only once.
Here’s the protocol syntax with associatedtype:
1 2 3 4 5 |
protocol ProtocolName { associatedtype TypeName mutating func append(_ item: TypeName) } |
Implementation of Associated Types
First, we’re going to extend the Vehicle protocol and it has an associatedtype called Type. Vehicle protocol that can store any type those items depend on whatever conforms to the protocol, but we can still use them inside the protocol and any extensions.
1 2 3 4 |
protocol Vehicle { associatedtype Types func call(type: Types)-> Types } |
Now conform to the Vehicle protocol on ByRoad, BySKy and ByWater struct. All are different types as
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
struct ByRoad : Vehicle{ var types: Bus func call(type: Bus) -> Bus { return type } } struct BySky: Vehicle{ var types: Helicopter func call(type: Helicopter) -> Helicopter { return type } } struct ByWater: Vehicle { var types: Ship func call(type: Ship) -> Ship { return type } } struct Bus { var bus: String init(bus: String) { self.bus = bus } } struct Helicopter { var helicopterName: String var helicopterModel: Int init(helicopterName: String, helicopterModel: Int ) { self.helicopterName = helicopterName self.helicopterModel = helicopterModel } } struct Ship { var shipName: String var shipModel: Float init(shipName: String,shipModel: Float ) { self.shipName = shipName self.shipModel = shipModel } } |
Let’s handle the cases for Vehicle protocol.
1 2 3 4 5 |
enum Way{ case byRoad case bySky case byWater } |
Now we’re going to define a function like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
func selectRoadWay() -> some Vehicle { // <-- Doesn't know type of `Vehicle` here. return ByRoad(types: Bus(bus: "bus")) // <-- Here it does get the type `Vehicle`. } func selectSkyWay() -> some Vehicle { // <-- Doesn't know type of `Vehicle` here. return BySky(types: Helicopter((helicopterName: "Heli 2", helicopterModel: 10)) // <-- Here it does get the type `Vehicle`. } func selectWaterWay() -> some Vehicle { // <-- Doesn't know type of `Vehicle` here. return ByWater(types: Ship(shipName: "Jack Ships", shipModel: 64.0) // <-- Here it does get the type `Vehicle`. } func selectWay(way: Way){ switch way { case .bySky: let skyWay = selectSkyWay() print(skyWay) case .byRoad: let roadWay = selectRoadWay() print(roadWay) case .byWater: let waterWay = selectWaterWay() print(waterWay) } } |
The returns a value of type Vehicle and uses some keyword to denote that this is an opaque type. Above written function returning the different values in the bodies. Output as,
1 2 3 4 5 6 7 8 |
let byWater = selectWay(way: .byWater) //Output: ByWater(types: Opaque_Type.Ship(shipName: "Jack Ships", shipModel: 64.0)) let byRoad = selectWay(way: .ByRoad) //Output: ByRoad(types: Opaque_Type.Car(car: "Car")) let bySky = selectWay(way: .BySky) //Output: BySky(types: Opaque_Type.Helicopter(helicopterName: "Heli 2", helicopterModel: 10)) |
Conclusion
I hope this blog will help you in the understanding of Associated Types in Swift Protocols if still you have any comments, questions, or recommendations, feel free to post them in the comment section below!
For other blogs, please click here.