この本を見ながら進めてる↓
前回⇒「【Swift奮闘記ep18】列挙型について(列挙型の定義やswitch文を使ったマッチング)」
“プロトコル”という言葉を聞いただけで、拒否反応が出てしまうくらいプロトコルには複雑そうなイメージを持っている。詳しくは全然知らないけど。
今回はなんとか少しでも理解してプロトコル攻略していきたい。
プロトコルとは
プロトコルとは特定のプロパティやメソッドを持たせるための取り決め、とのことだがなんのことだかさっぱりわからん。クラスやストラクチャに制約をもたせて作成させることができる、と言われて少しフムフム納得。
プロトコルって俺の理解だと「約束」っていう感覚。
約束をいくつか定義して、例えば「nameというプロパティを使う」「run( )というメソッドを使う」とかね。
あと、クラスやストラクチャにその約束を守らせることを「プロトコルに準拠させる」という。
プロトコルを使う理由
なんでプロトコル使うのって話だけど
プロトコルのメリットってインスタンスを「プロトコルに準拠した何か」として取り扱うっことができる点にある
というメリットがある。
そういわれてもよくわからんだろうけど、例えば「nameというプロパティを使う」というプロトコルを準拠してクラスを作成した場合、それからインスタンス化されるものはどのような型のインスタンスであってもnameプロパティを扱える前提となる。
それって超便利じゃん?って話だ。
例えば、ある工場Aで作られたパソコンは全てMicrosoftOfficeが入っているから、そのパソコンの持ち主にはEXCELファイルを見れることを前提にデータ送信ができるよ!みたいな感じだろうか笑
今日チームのメンバーには「12時までにはグラウンドにサッカーシューズ履いて来るように」って言っといたから、13時からみんなでサッカーできる!みたいな。
みんなある一定の条件のもとで動いてくれてるとわかっていた方が、まとめやすいよね。そんな話。
プロトコルの定義と準拠
プロトコルを定義する方法については先頭にprotocolと文字を入れるだけで簡単にできる。
プロトコルに準拠したクラスの定義をする際は、継承と同じようにクラス名:プロトコル名とする。
さらに継承しつつプロトコルに準拠させたい時は(サボらずちゃんと書くと)「class クラス名:スーパークラス名,プロトコル名{ }」となる。
プロパティの定義
プロトコルのプロパティ
var プロパティ名:型 { get set }
取得・代入することができる場合はgetとsetを、取得のみさせる場合にはgetのみを。
setのみにはできないので注意。
と言われてもピンとこないと思うので、実際にコードを打っていく。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
protocol NumberPlate { var number: String { get } //読み取り専用のプロパティnumberを定義 } //NumberPlateプロトコルに準拠したクラスを定義してみる。 class JapaneseCar: NumberPlate { var place = "" var group = "" var kana = "" var car = "" var number: String { return "\(place) \(group) \(kana) \(car)" } } //インスタンス化していく let car = JapaneseCar() car.place = "札幌" car.group = "330" car.kana = "お" car.car = "7774" car.number |
といっても特にひねりもなく、継承となんか似てるな〜くらいに思って進めるだけでいいんかなって思う。
※追記
いやいや!全然違うだろ!w
NumberPlateプロトコルで、「変数numberは読み取り専用で使いましょう」と設定。
それを準拠させたJapaneseCarクラスでは変数numberをナンバープレートが表示されるように設定。
値は代入することはできない。(number = 5とかはできないということ)
インスタンス化したら、それぞれのプロパティのまとめた値が戻り値で帰って来る。
メソッドの定義
プロトコルにメソッドを定義する場合、(プロトコルを準拠させる)クラスを定義するときにメソッドの具体的な内容(処理)を定義する。
つまりプロトコルでは「Aというメソッドを使ってください」という指示を出すだけで、クラスによって処理の内容が違うのである。
例えばあるクラスではcountに1ずつ足されていく処理がメソッドAの中身だったり、違うクラス内ではメソッドAはcountが1ずつ減ってく処理かもしれない。
プロトコルに準拠させるってことは「メソッドAが入るっていうだけの制約で、Aの中身については制約されていない。
具体的に見ていこう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
protocol Horn { func sound(count: Int) -> String } class FamilyCar: Horn { func sound(count: Int) -> String { var horn = "" for _ in 1...count { horn += "pupu--" } return horn //戻り値をhornに設定 } } let car = FamilyCar()//インスタンス化 car.sound(count: 4) //引数countに4を代入しつつメソッドsoundを実行 |
sound(サウンド)というメソッドを作ることを約束したプロトコル。
FamilyCarクラスはそのプロトコルに準拠しているので、soundメソッドを設定する。
soundメソッドの内容は「pupu–という音を鳴らす」と設定。
試しにもう1個のクラスを定義してみる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
protocol Horn { func sound(count: Int) -> String } class Truck: Horn { func sound(count: Int) -> String { var horn = "" for _ in 1...count { horn += "bubu--" } return horn } } let car = Truck() car.sound(count: 2) //引数countに2を代入しつつメソッドsoundを実行 |
今度はbubu–と音がなるように設定された。
このようにメソッドの内容は違うけれども、どちらもちゃんとプロトコルに準拠している。
プロトコル前半戦はとりあえずここまで
コメント