Swift 押さえておきたい構文 「Protocol」で”できる事”
筆者がいろんな言語を使用してきて、他の言語と異なる気になると感じたSwiftで押さえておきたい構文を「なにが出来るの?」といった視点で紹介していきます。
今回はProtocolについて公式サイトの説明を使用しながら解りやすく解説していきます。
ProtocolはExtensionとして記述する事でProtocolに準拠した内容を明示的に記述できるのでExtensionと組み合わせて使用するようにするとおすすめです。
Protocol?
・プロトコルは、特定のタスクまたは機能に準拠するメソッド、プロパティおよびその他の要件を満たすためインターフェースを定義します。実際の処理などは記述しません。
➡共通使用できる決まり事を定義する
・プロトコルの要件を満たすタイプは、そのプロトコルに準拠しているといいます。
クラス、構造体、列挙型で準拠することができます。
➡定義したインターフェースを使用るしている場合”準拠している”と言う
Protocolで”できる事”
・共通使用する型、メソッド、プロパティのインターフェースなどを共通認識の定義することができる。
・共通のI/Fを定義することによりエンジニア間でI/Fの認識を統一できる。
定義
プロトコルを定義できるタイプ
- 構造体
- メソッド
- 列挙型
protocol PrefixProtocol {
// プロトコルの定義
var mrName: String {get} // Struct 構造体
func prefixName() -> String // メソッド
}
使用方法(準拠方法)
・構造体
構造体名の後ろにプロトコル名をコロンで区切って配置します。
複数のプロトコルにも準拠でき、カンマで区切り配置。
・クラス
スーパークラスがある場合は、スーパークラス名の後にカンマ区切りで配置。
class SampleClass: SampleSuperClass, PrefixProtocol , SecondProtocol{
// クラス定義
}
・列挙型
列挙型名の後ろにプロトコル名をコロンで区切って配置します。
enum SamplleEnum:PrefixProtocol , SecondProtocol{
// 列挙型定義
}
使用例(準拠例)
・構造体
★getのみのケース
次のケースでは税込み価格のプロパティをIncludingTaxプロトコルで定義します。
準拠したクラスProductでは、withTaxをgetterにてpriceの値にrateをかけた値を返す実装を行い税込み価格となるよう実装しています。
protocol IncludingTax{
var withTax: Int{ get }
}
class Product: IncludingTax {
var name: String
var price: Int
var rate: Double
var withTax: Int {
return Int( price * rate )
}
init(name: String, price: Int, rate: Double = 1.1){
self.name = name
self.price = price
self.rate = rate
}
}
var banana= Product(name:"Banana", price: 100, rate: 1.08 )
// banana.withTax is "108"
★get,setの場合
protocol OddNumber {
var number: Int { get set }
var nextOdd: Int { get }
}
struct SampleStructure: OddNumber {
var number: Int = 0
var nextOdd{
get {
if 0 != number % 2 {
return number + 2
}
return number + 1
}
}
}
print( SampleStructure().nextOdd )
// 1
・メソッド
次の例では、名前に敬称をつけるプロトコルPrefixProtocolを定義し、準拠するクラスCustomerManagerで敬称を付加する処理を実装しています。
// プロトコルの定義
protocol PrefixProtocol {
func getPrefixName() -> String // メソッド
}
class CustomerManager: PrefixProtocol {
var firstname: String = "Jon"
var prefix: String = "Mr."
func getPrefixName() -> String{
return prefix + firstname
}
}
print( CustomerManager().getPrefixName())
// Mr.Jon
※イニシャライザ
プロトコルに準拠するために特定のイニシャライザが必要な場合、通常のイニシャライザと同じ方法でプロトコルとして定義可能です。他のプロトコルと同じように定義に中括弧やイニシャライザ本文はありません。
準拠するクラスでのイニシャライザは`required‘修飾子をつける必要があります。
次の例では敬称プロトコルPrefixProtocolにprefixを初期化するプロトコルを定義し、準拠するクラスSomeClassでprefixを引数で初期化するサンプルになります。
protocol PrefixProtocol {
var prefix: String
init(prefix: String)
}
class SomeClass: SomeProtocol {
var firstname = "Bell"
required init(prefix: String) {
self.prefix = prefix
}
func getPrefixName() -> String{
return prefix + firstname
}
}
print( CustomerManager("Mss").getPrefixName())
// Mss.Bell
・列挙型
mutating
構造体と列挙型のインスタンスメソッドが属するインスタンスを変更する場合、メソッドのfunc‘キーワードの前に
mutating` キーワードを配置しプロパティを変更できることを宣言します
参考:Swift公式
「Enum」で”できる事”について以下の記事で紹介していますのでよかったら参照してみてください。