post Image
SwiftのExtensionによるクラス分割

やっている人には何を今更と言われそうですが、しばらく使ってみて思ったことが幾つかあったのでまとめてみます。
間違い、意見、感想、自分はこんなふうに使ってるよ!等ありましたらぜひコメントお願いします。
使用しているXcodeは8.3.3です。

どんなふうに使うの?

一つのクラスをExtensionを使って複数に分けて書きます。自分は大体次の基準で分けます。
あくまで大体の基準で、一つのExtensionが長くなってきたなとか思えば分けることもあります。そこは柔軟に。

  • プロパティと初期化、ライフサイクル
  • UI関連の処理
  • 各種プロトコルの実装
  • (ボタンなどの)アクション
  • アニメーション
  • 通信/ストレージ系
  • などなど…

例えばVCのコードでは以下の感じ。内容は適当です。

サンプル
import UIKit

// MARK: vars and lifecycle
class ViewController: UIViewController {

    @IBOutlet fileprivate weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.setupUI()
    }
}

// MARK: - UI
extension ViewController {

    fileprivate func setupUI() {
        self.setupHeader()
        self.setupTableView()
    }

    private func setupHeader() {
        self.title = "hoge"
        self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "fuga", style: .plain, target: self, action: #selector(self.didTapRightBarButton(_:)))
    }

    private func setupTableView() {
        self.tableView.dataSource = self
        self.tableView.delegate   = self
    }
}

// MARK: - UITableViewDataSource
extension ViewController: UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        return UITableViewCell()
    }
}

// MARK: - UITableViewDelegate
extension ViewController: UITableViewDelegate {

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        // do something
    }
}

// MARK: - actions
extension ViewController {

    func didTapRightBarButton(_ sender: UIBarButtonItem) {
        // do something
    }

    @IBAction func didTapButton1(_ sender: UIButton) {
        // do something
    }

    @IBAction func didTapButton2(_ sender: UIButton) {
        // do something
    }
}

良いと思うこと

見通しがよくなる

コードをパッと見た時にかたまりが分かります。コメントで区切る方法もあると思いますが、個人的にはそれより見た目がきれいだと思います。

関連する処理をまとめられる

UIに関連する処理、デリゲートとそのヘルパーメソッド、など近い処理をまとめて書いておくことで読みやすいコードになります。

privateのスコープが狭くなる

あるメソッドのためのヘルパーメソッドなど、クラス全体に見えなくても良いプロパティ/メソッドを作ることがあると思います。
そんな時にExtensionで分けてprivateをつけておくことで可視性を狭めることができます。

悪いと思うこと

タイプ量が多くなる

分けた分だけextension クラス名を書かなければいけないので若干面倒です。
基本コピペだし、遥かに利点の方が大きいので、気にする程ではないですが。

できたらいいなと思うこと

stored propertyの使用

Extension内ではstored propertyを定義することはできません。
computed propertyなら定義することができるので、毎回計算されても良いものはそちらを使います。
状態を保持しておきたいなんてときは、諦めてクラス定義のところにプロパティを書きます。
とあるExtensionでしか使わないプロパティがちょいちょい出てくるので、定義できるようにならないものでしょうか。

IBOutlet/IBActionを直接接続

IBからcontrol+ドラッグで線を引っ張ってきても、Extension内では反応してくれません。
コードの方で@IBAction func didTapButton1(_ sender: UIButton) { ...みたいなのを手書きして、保存した時に現れる丸をIBへ引っ張れば接続することができます。
若干の手間なので、Extensionに引っ張れるようにならないものでしょうか。

1.png

2.png

プロトコルを実装する場合の場所の制限

どこかのExtensionでプロトコルの実装を宣言しても、あくまでそのクラスがプロトコルを実装するということを宣言しただけです。
つまり、宣言したものとは別のExtensionで実装することもできます。

こんなことができる
// プロトコルの実装は宣言するけど中身はなし
extension ViewController: UITableViewDataSource {}

// こちらでUITableViewDataSourceを実装する
extension ViewController {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        return UITableViewCell()
    }
}

まあ書く人が気をつけましょうという話ですが、宣言した場所で実装もしなければならない、とするのは難しいのでしょうか。

おわりに

同じものをまとめる、違うものを分ける、と言うのは設計の基本だと思います。
MV~などと比べれば小さな話かもしれませんが、こういうちょっとしたことでコードの読みやすさは変わると思うので、より良い方法を模索して行きたいです。


『 Swift 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。