SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Swift 4で最初に知っておきたい3つのポイント

「Swift 4」でのアプリ開発を始める前に知っておきたい、基本の「き」

Swift 4で最初に知っておきたい3つのポイント 第1回

  • X ポスト
  • このエントリーをはてなブックマークに追加

クラスを拡張する【Swift 4】

 Swiftではクラスを拡張するextensionという機能があります。extensionを利用すると、新しいクラスを作成することなく既存のクラスに機能を付加することができます。またdelegateやdatasourceを継承した部分については、extensionを使って元のクラスとは別に記述することもできます。Swift 4以降では、privateで定義したプロパティにも、extensitonで拡張した部分からアクセスできるようになりました。extension自体はSwift 4以前に実装された機能ですが、アプリ開発を行う上で知っておくべき重要な機能なのでサンプルをあげながら説明します。

既存クラスにメソッドを追加する

 既存のクラスに開発者が作成したメソッドを追加することで、新しいクラスを作成することなくXcodeのプロジェクト全体で共通して機能を利用することができます。UIImageを円で表示したい場合、次のようにUIImageクラスを拡張することで機能を実装できます。

リスト7 UIImage+Extension.swift(UIImageクラスを拡張)
extension UIImage {   // ---------(1)
    // UIImageを円形に
    func circle() -> UIImage {   // ---------(2)
        // 縦横小さい方を優先して矩形を定義
        let rect = CGSize(width: min(size.width, size.height), height: min(size.width, size.height))
        // UIImageViewを生成して矩形の半分のサイズで角丸に
        let imageView = UIImageView(frame: CGRect(origin: .zero, size: rect))   // ---------(3)
        imageView.contentMode = .scaleAspectFill
        imageView.image = self
        imageView.layer.cornerRadius = rect.width/2
        imageView.layer.masksToBounds = true
        // UIImageViewから画像として出力
        UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, scale)   // ---------(4)
        let context = UIGraphicsGetCurrentContext()
        imageView.layer.render(in: context!)
        let result = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return result!
    }
}

 UIImageクラスを拡張することをextension修飾子で宣言します(1)。実装したい機能を通常のメソッドと同様に定義します(2)。UIImageを円形にするためには、いったん形状の変更が容易なUIImageViewを生成し(3)、UIImageViewのサイズが半分のところで角丸にします。角丸になった矩形の4隅が組み合わさって円ができます。そのあとにUIGraphicsGetCurrentContextの機能を使って画像として出力します(4)。

 作成したメソッドを実際に利用する際には、UIImageオブジェクトの後ろでcircle()メソッドを実行します。

リスト8 CatViewController.swift(画像を円形に表示)
// UIImageを初期化
let image = UIImage(named:"cat")?.circle()  // 作成したcircle() メソッドを実行

 サンプルの実行結果は次の通りです。

画像を円形に表示
画像を円形に表示

 既存のクラスを拡張したメソッドの実装なので、特別な処理は必要なく、既存クラスのメソッドと同じように利用できます。extensionをうまく使うことで、余計なクラスを作成することなく既存のクラスを拡張して機能を作成可能です。

ソースコードを分離して記述する

 delegateやdatasourceを実装した部分もクラスのextensionで扱うことができます。このことを利用すると、delegateやdatasourceを実装する際には、extensionを使って本来のクラスとは分けてソースコードを記述可能です。サンプルの最初のページで表示しているUITableViewをUIViewControllerクラスで実装する際には、次のようにソースコードを分けて記述できます。

リスト9 ViewController.swift(実装したdelegateとdatasourceを分けて記述する例)
class ViewController: UIViewController {
    private let Identifier = "Cell"
    private let items = ["UIImageViewサンプル", "MKMapViewサンプル"]
# 中略
// ViewControllerクラスの画面表示等の本来の処理のみを記述
}

// UITableViewDelegateを実装した部分
extension ViewController : UITableViewDelegate {   // ---------(1)
    // テーブルのセル選択時の処理
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {   // ---------(2)
        // Main.storyboardを取得
        let storyBoard = UIStoryboard(name: "Main", bundle: nil)
        let row = indexPath.row
        if row == 0 {
            // CatNavigationViewControllerのIDのViewControllerを取得してモーダル表示
            let vc = storyBoard.instantiateViewController(withIdentifier: "CatNavigationViewController")
            self.present(vc, animated: true, completion: nil)
        }else{
            // MapViewControllerのIDのViewControllerを取得して画面遷移
            let mapVC = storyBoard.instantiateViewController(withIdentifier: "MapViewController")
            self.navigationController?.pushViewController(mapVC, animated: true)
        }
    }
}

// UITableViewDataSourceを実装した部分
extension ViewController : UITableViewDataSource {   // ---------(3)
    // テーブルのセル数
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {   // ---------(4)
        return items.count
    }
    
    // テーブルに表示するセル
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {   // ---------(5)
        let cell = tableView.dequeueReusableCell(withIdentifier: self.Identifier)
        cell?.textLabel?.text = items[indexPath.row]
        return cell!
    }
}

 ViewControllerクラスでUITableViewDelegateとUITableViewDataSourceを実装した部分を、extensionで分けて記述します(1)(2)。実装するdelegateとdatasourceは、クラスに実装する際と同じようにクラス名のあとに「:」で区切って記述します。実装したUITableViewDelegateとUITableViewDataSourceのメソッドは、それぞれのextensionの中に記述します(3)(4)(5)。それ以外の部分に記述すると実行されないので気をつけてください。(4)(5)のUITableViewDataSourceのメソッド内では、ViewControllerクラスで定義した変数を参照しています。このようにextensionで拡張した部分からも、本来のクラスの変数やプロパティを参照することができます。

 UITableViewDelegateとUITableViewDataSourceを実装した部分をextensionで分けて記述することで、元のクラスの処理と実装したdelegateとdatasourceの処理を分けることができます。これによってソースコード内のどこでどのような処理を行っているかがわかりやすくなり、ソースコードの保守性が上がります。

まとめ

 今回はSwiftの簡単なプログラミング、追加された代表的な機能の確認を行いました。次回は実際にSwiftでクラスやメソッドの作る方法等について説明を行う予定です。

参考資料

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
Swift 4で最初に知っておきたい3つのポイント連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 片渕 彼富(カタフチ カノトミ)

WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS Twitter: @yyamada(公式)、@yyamada/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/10500 2017/11/09 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング