はじめに
swiftの勉強を始めてみると、今まで使ったことのないコードや機能に出会うことが多いです。今回はその中の1つextensionの紹介をします。
修正点などありましたら、指摘していただくと嬉しいです。
extensionとは
extension 「拡張」という言葉の通り、クラス(class)や構造体(struct)
プロトコル(protocol)などに、関数(メソッド)や変数(プロパティ)を追加することができる機能です。
それなら普通にクラスや構造体にコードを追加すればいいじゃないかと思いますが(自分も思いましたが)、それ以上の機能や便利な面もあるので、使いこなしていきましょう。
まずは基本的なことから行きます。
具体的な書き方
extension 拡張する型の名前 {
//追加するメソッドやプロパティを記述する
}
書き方は簡単です。
拡張したいクラスや構造体の名前と、追加のメソッドやプロパティを記述します。
自分で定義したクラスなどを入れて、新しいメソッドを追加することが簡単にできます。
extensionの記述例
最初に言ったように、自分で作ったクラスや構造体ならその部分にコードを直接記述すれば、メッソドとプロパティは追加できます。しかし、自分で定義していないもの(元々存在しているもの)に関してはその操作ができません。
そこでextensionの1つ目の素晴らしい点が、自分が作ったものでなくてもSwiftに元々あるクラスなどにも機能を拡張することができるという点です。例えばとても身近なIntやStringといったクラスに新たなメソッドを定義することができます。
extension Int {
func niceNumber() {
print("Wow! Nice number!")
}
}
このようなおかしなメソッドも追加することができ、実際に使うことができます。
let number = 5
number.niceNumber() //=> Wow! Nice Number!
これはextensionを使わないとできないことだと思います。
ちなみにIntやStringはオープンソースになっていて、GitHub上で誰でも中身を見ることができます。またUITextFieldなどはオープンソースではないですが、もちろん拡張することはできます。
プロトコルの拡張
素晴らしい点2つ目は、プロトコルの拡張です。
プロコトルというのは、メソッドやプロパティの中身を定義することができませんでした。そのため、それぞれのプロトコルを適用したクラスなどで中身を書いていく必要がありました。
//プロトコルの定義
protocol Canfly {
func fly()
}
//プロトコルを適用しているクラス
class Eagle: Canfly {
func fly() {
print("The eagle can fly")//1つ1つメソッドの処理を書く
}
}
//プロトコルを適用しているクラス
class Airplane: Canfly {
func fly() {
print("The plane can fly")//1つ1つメソッドの処理を書く
}
}
ところがextensionを使うことで、その中身を事前に定義することができるのです。
書き方は今までと一緒です。
上記の例をそのまま使うと
extension Canfly {
func fly() {
print("The object can fly")
}
}
こうすることによって、Canflyプロトコルのflyメソッドの中身を定義することができました。
すると
class Eagle: Canfly {
//fly()メソッドの定義をしなくても大丈夫
}
class Airplane: Canfly {
//fly()メソッドの定義をしなくても大丈夫
}
let myEagle = Eagle()
let myPlane = Airplane()
myEagle.fly() //=> The object can fly
myPlane.fly() //=> The object can fly
このようにして、コードの量や負担を減らすことができました。
今まで既存のプロトコルを適用する際に、全部のメッソドを呼び出したり定義していないのに大丈夫なのかなと思っていた方も多いと思いますが、それらは全てextensionをつかってappleさんが事前に定義してくれているから大丈夫なんです。
コードを見やすくする
extension最後の活用方法は、extensionを使うことでコードがすっきりして見やすくなります。
具体的には以下のように、1つのクラスにたくさんのプロトコルを適用している場合、どのメソッドがどのプロトコルに対応している操作なのか、コードが膨大になり分わかりにくくなります。
import UIKit
// プロトコルを2つも適用している、、、
class WeatherViewController: UIViewController, UITextFieldDelegate, UINavigationControllerDelegate {
@IBOutlet weak var conditionImageView: UIImageView!
@IBOutlet weak var temperatureLabel: UILabel!
@IBOutlet weak var cityLabel: UILabel!
@IBOutlet weak var searchTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
.......
}
//どのメソッドが
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
.....
}
//どのプロパティに対応しているのか
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
......
}
//多すぎてわからなくなる
func textFieldDidEndEditing(_ textField: UITextField) {
.......
}
//なんの操作をしているだろう
func navigationController() {
........
}
}
そこでextensionを使うことで、プロトコルごとにコードを記述する場所を分けるのです。
具体的には以下のようにすることができます。
import UIKit
class WeatherViewController: UIViewController, UITextFieldDelegate, UINavigationControllerDelegate {
@IBOutlet weak var conditionImageView: UIImageView!
@IBOutlet weak var temperatureLabel: UILabel!
@IBOutlet weak var cityLabel: UILabel!
@IBOutlet weak var searchTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
.......
}
}
//プロトコルごとに分ける----------------------------------------------------------------------------------
extension WeatherViewController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
.....
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
......
}
func textFieldDidEndEditing(_ textField: UITextField) {
.......
}
}
//プロトコルごとに分ける----------------------------------------------------------------------------------
extension WeatherViewController: UINavigationControllerDelegate {
func navigationController(........) {
........
}
}
これでプロトコルとメソッドの対応関係もしっかり分かり、コードもすっきりしました。
以上でextensionの使い方等の解説を終わります。これはプログラミング初心者が簡単にまとめたものなので、修正などがありましたらご指摘お願いします。