Not too long ago I briefly mentioned the use of protocol as the way of Protocol Oriented Programming.
Protocol is fantastic.
Here is a guide on some of the common use of this Swift “feature”.
Declaring a Protocol
Protocol are likes classes. You need to give it a name.
You will commonly find names with -able suffixes eg. TextRepresentable
.
Let’s use a make up example of Codable
, a protocol with a single function code
:
protocol Codable {
func code(text: String) -> Bool
}
Any class now that extends Codable
will require the code
method.
Default Extension
Having a default extension
makes things very convenient to use.
For example, the default implementation below will always return true.
extension Codable {
func code(text: String) -> Bool {
return true
}
}
Now, any type that implements the Codable
protocol get the default implementation, for FREE!
Of course, you may still implement your own (and not use the default).
Default Extension with Type
Now, suppose you want the default extension to use a UIViewController
method.
You can enforce that the default extension be of the type UIViewController
.
extension Codable where Self: UIViewController {
func code(text: String) -> Bool {
return self.view.hidden // self is now a UIViewController!
}
}
Of course, now any type that implements the Codable
protocol must be a UIViewController
, if it wants the default implementation.
Optional methods
If you want a protocol method, you can try to add optional
attribute to the func
. But that will give the error:
‘optional’ can only be applied to members of an @objc protocol
The Swift way is slightly more tedious. You have to add a default extension, which is already covered in the section above!
The code
method in the section Default Extension makes the method optional.
Protocol of class type
You may enforce that a protocol is to be use by classes only (sorry structs and enums).
protocol Codable: class { ... }
This is needed especially for the scenario where you need a protocol to be weak
(to avoid retain cycle). Because:
weak can only be applied to class or class-bound protocol.
Associated Types - Using Self
Think of associated types as a placeholder for an unknown type.
You can use Self
in the protocol declaration to refer to the actual type that implements it.
protocol Codable {
func code(foo: Self) -> Bool
}
So if later your UIViewController
implements it, foo
can be of the actual type.
extension MyViewController: Codable {
func code(foo: MyViewController) { ... }
}
Associated Types - Using associatedtype
You could in fact declare any generic type for a protocol.
Here, we declare Code
as a generic type to be used in the protocol.
protocol Codable {
associatedtype Code
func code(foo: Code) -> Bool
}
Now, you can implement the actual type of Code
. We use Int
in this example:
class ActualCodable: Codable {
func code(foo: Int) -> Bool {
return foo > 10
}
}
You can make the protocol more readable if foo
does not describes your parameter name well. In the protocol declaration, you can use _
instead of naming it foo
, then in implementation use any name you want.
Protocol is powerful :)