[Swift] Protocol concept and definition method

A protocol defines a ** type interface. ** ** An interface is an indication of what properties and methods a type has.

How to define a type interface

Protocols define the interfaces required for a type to have a particular property or function. Also, the fact that the type meets the interface required by the ** protocol is called compliance. ** **

Occasionally appears in my article, "The XX type conforms to the △△ protocol, so you can use this method." The phrase means that.

** Protocols can be used to abstract properties that are common to multiple types. ** **

For example, whether or not two values ​​are equivalent is called equivalence. The property that equivalence is detectable is It is represented by the Equatable protocol of the standard library.

Equivalence, the ** == operator **, is defined in the Equatable protocol. And those who comply with the Equatable protocol need to define an implementation for the == operator.

I get a lot of benefits thanks to the protocol, One of them makes it possible to handle only types that comply with the ** protocol. ** **

In the following sample code I specified two function arguments and output whether the values ​​are the same, The types of arguments that can be passed are limited to types that comply with the Equatable protocol.

The restricted part is the part of func equate <T: Equatable> (...). ** T type is a type that conforms to the Equatable protocol. I am limiting. ** ** (It can be executed with A or B instead of T. It seems that there is a tendency to use T ...)

This time, the value passed to the argument will be Int type or String type, These types are Equatable protocol compliant and can be executed.

As it says (_ value1: T, _ value2: T) Since the argument type is unified with T type for the first argument and the second argument, Passing a different type as an argument will result in a compilation error.


func equate<T: Equatable>(_ value1: T, _ value2: T) {
    if value1 == value2 {
        print("The values ​​are the same.")
    } else {
        print("The values ​​are different.")
    }
}

equate("abc", "abc")
equate(1, 1)
equate(1, 2)
// equate(1, "1")   //Compile error

Execution result
The values ​​are the same.
The values ​​are the same.
The values ​​are different.

Protocol basics

Explains how to define, comply with, and use the protocol.

Definition method

The protocol is declared using the protocol keyword and Define ** components ** such as properties and methods in {}.

The components will be described later.


protocol protocol name{
Protocol definition
}

Compliance method

By conforming to the protocol, the type It can be handled through the interface defined by the protocol.

To make the type conform to the protocol, write as follows. (This time, the structure conforms to the protocol.)

In addition, it is possible to comply with multiple protocols by separating them with ,.


struct structure name:Protocol name 1,Protocol name 2 ・ ・ ・{
Structure definition
}

To comply with the protocol ** Implementations must be provided for all interfaces required by the protocol. ** **

If you defined the method in the protocol, as in the following sample code Those who adhere to that protocol must define the same method in the type.

** If it is not defined, a compile error will occur. ** **


protocol SampleProtocol {
    func sampleMethod()
}

struct Sample: SampleProtocol {
    func sampleMethod() { }
}

struct Sample2: SampleProtocol { }   //Compile error

Error details: Type'Sample2' does not conform to protocol'SampleProtocol' Japanese translation: Type "Sample2" does not comply with protocol "Sample Protocol"

Compliance method when inheriting a class

It is possible to comply with the protocol not only in structs but also in classes, I don't know if it's a superclass or a protocol with the definition method I mentioned earlier.

In fact, there is a rule, and if you want to inherit and comply with the protocol at the same time, ** You need to write the inherited superclass name first, then the protocol. ** **


class class name:Super class,Protocol name 1,Protocol name 2 ・ ・ ・{
Class definition
}

How to comply with extensions

Protocol compliance can also be achieved with extensions. Here's how to add a compliant protocol with an extension.


extension The type that defines the extension:Protocol name{
Definitions required by the protocol
}

It is also possible to make multiple protocols compliant for one extension. I think this will be different for each person, but ** I think it's better to have one at a time to improve readability. ** **

Because if you comply with multiple protocols at once, This is because it is difficult to understand which protocol the definition is for.

The amount of code will increase, but if you comply with one protocol with one extension, ** It will be easier to understand which protocol declares the content. ** **

Since there is a possibility that people other than yourself will also maintain it, Should I divide it to improve readability? I think.

The actual description is as follows.


//First protocol
protocol SampleProtocol1 {
    func sampleMethod1()
}

//Second protocol
protocol SampleProtocol2 {
    func sampleMethod2()
}

//Structure
struct Sample {
    let a = 1
}

//Extension 1st
extension Sample: SampleProtocol1 {
    func sampleMethod1() { }
}

//Second extension
extension Sample: SampleProtocol2 {
    func sampleMethod2() { }
}

Compliance check by compiler

Whether a type that conforms to a protocol meets the requirements of that protocol It is checked by the compiler, and if even one is missing, a compilation error will occur.

In the following sample code There is a Sample type that conforms to the SampleProtocol, The sampleMethod () defined in the protocol is not defined in the structure.

In this case, you will get a compilation error because you do not meet the requirements.


protocol SampleProtocol {
    func sampleMethod()
}

struct Sample: SampleProtocol{ }

Error details: Type'Sample' does not conform to protocol'SampleProtocol' Japanese translation: Type "Sample" does not comply with protocol "Sample Protocol"

How to Use

Protocols are similar to structs, classes, enums, closures, It can be used as a variable / constant / argument type.

Protocol-compliant types can be upcast to a protocol.

Therefore, the following sample code can be processed.

When a protocol is specified for the argument type, such as func sample (x: SampleProtocol) ** Only types that conform to Sample Protocol can be passed as arguments. ** **

Like x.value Another feature is that you can use the properties and methods defined in the protocol.

If you pass a type that does not conform to the protocol as an argument, I get a compile error.


protocol SampleProtocol {
    var value: Int { get }
}

struct Sample: SampleProtocol{
    var int: Int
    var value: Int {
        return int * 10
    }
}

//Specify protocol as argument type
func sample(x: SampleProtocol) -> Int {
    //Among the properties and methods of the argument x
    //You can use the one defined in Sample Protocol
    x.value
}

let a = 1    //Int type
let b = Sample(int: 2)    //Sample type

sample(x: a)    //Compile error
sample(x: b)    // 20

Error details: Argument type'Int' does not conform to expected type'SampleProtocol' Japanese translation: Argument type "Int" does not conform to the expected type "Sample Protocol"

** Protocols with associative types cannot be used as variables, constants, or argument types. It can only be used to describe type constraints for generic type arguments. ** ** (Associative types and generics will be explained in a separate article.)

Protocol composition

Protocol composition is a mechanism for expressing types that conform to multiple protocols. ** ** To use it, describe multiple protocol names separated by &.

In the following sample code The argument specifies a type that complies with both Protocol1 and Protocol2.

So, like x.value1 + x.value2, You can use the properties defined in each protocol.


protocol Protocol1 {
    var value1: Int { get }
}

protocol Protocol2 {
    var value2: Int { get }
}

struct Sample: Protocol1, Protocol2 {
    var value1: Int
    var value2: Int
}

func plus(x: Protocol1 & Protocol2) -> Int {
    x.value1 + x.value2
}

let sample = Sample(value1: 10, value2: 5)
plus(x: sample)    // 15

If you want to comply with multiple protocols There is no need to unify the types, and you can write the following code.


protocol Protocol1 {
    var value: Int { get }
}

protocol Protocol2 {
    var name: String { get }
}

struct Sample: Protocol1, Protocol2 {
    var value: Int
    var name: String
}

func plus(x: Protocol1 & Protocol2) {
    print("\(x.name)Is\(x.value)He gave me a yen.")
}

let sample = Sample(value: 1000, name: "Kondo")
plus(x: sample)

Execution result
Mr. Kondo gave me 1000 yen.

The above is the concept of the protocol, how to define it, and how to use it. I'm sorry it's been a little longer.

The protocol appears frequently and I think it is a compulsory subject, so please be sure to use it!

In addition to this article, there is an article that explains the protocol, so If you have time, please see that as well.

-[Swift] Protocol elements -[Swift] Protocol Extension

Thank you for watching until the end!

Recommended Posts

[Swift] Protocol concept and definition method
[Swift] About protocol extension
[Swift] Protocol concept and definition method
[Java / Swift] Comparison of Java Interface and Swift Protocol
variable and method
definition of ruby method
[Swift] Constants and variables
[Swift] About protocol extension
[Ruby] Method definition summary
[Swift] Type component ~ Method ~
[Rails] require method and permit method
Ruby algorithm (inject, method definition)
Java class definition and instantiation
Use swift Filter and Map
Basic knowledge in method definition
[Java] Introductory structure Class definition Relationship between class and instance Method definition format