CodeZine(コードジン)

特集ページ一覧

【デブサミ2016】18-A-4レポート
肥大化したObjective-Cコードは設計から見直す! ヤフーのiOSアプリ事例で学ぶSwift対応のポイント

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2016/03/25 14:00

目次

Swift脳になるための3つのポイント

 よりSwift風なコードを書くために、佐野氏は「書き方以外にもコツがある」と語る。まずWWDCで語られていた「Swift=“Objective-C without the C”」ではなく、Objective-Cにはなかった新しい考え方、特にSwiftの癖を理解する必要がある。そこを踏まえて、次のようなことを乗り越えると「Swiftと仲良くなれる」という。

 最初のコツは「Optional型と仲良くなる」こと。Appleのドキュメントでは、「Optional型は値の存在しないことをハンドルできるもので、値があるか、ないかのどちらかを表す。SwiftでOptional型を使うのは、Objective-Cでnilを使うようなもの」と書かれているが、そのつもりでSwiftに臨むと、nilの扱いを厳しく言われて「中身がある場合」の分岐が多数生まれて、期待した通りの美しいコードが書けなくなる。

 つまり、nilが入れられると考えるのではなく、中身の仕組みを理解する方がよいだろう。Optionalは任意の型を持てるジェネリックなenumで、Int?はOptionalと同じ。任意の値はOptional型への代入によってOptional型に暗黙キャストされる。これが便利でもあり、Optional型の、型の存在を分からなくする点でもある。そこを理解することがカギとなる。

 またSwiftのnilは、Objective-Cのnilとは異なりただのリテラルで、実態はOptional型の値Noneである。つまり「値を入れられる(入れなくてもいい)箱」というわけだ。佐野氏はさらに「もっと単純に考えて、Optionalは長さか0または1のArrayと思おう」と語る。

Optional型は「値を入れられる(入れなくてもいい)箱」
Optional型は「値を入れられる(入れなくてもいい)箱」

 つまり、SwiftはOptionalに対して限定的に暗黙キャストを認めており、Int?に代入された1は Optional.Some(1)、さらにnilはただのリテラルで、実態は Optional.None Obj-Cのnil(NULLポインタ)とは完全に別物と認識すべきだという。なお、if let/guard letは便利だが冗長になることが多い。そこで、関数型言語の特徴を利用すると、美しいコードが書けるというわけだ。

 というわけで、コツの二つ目は、多くの人は敬遠する傾向にある「関数型」を怖がらないことだ。関数をといっても、変数とは別のものと考えるのではなく一つのオブジェクトと考え、関数を変数に代入する、引数にとる、戻り値で返すことができるということである(このことを「第1級クラス」という)。たとえば、佐野氏がユニークな例としてあげたのが次のコードだ。

左:Swiftでの関数の代入の例、右:左の処理をわかりやすく書いたもの
左:Swiftでの関数の代入の例、右:左の処理をわかりやすく書いたもの

 左のコードは、Objective-Cでは見ない書き方だが、演算子そのものが関数として定義されており、sortは、引数に「ある型のものを2つ受け取って真か偽かを返す」という関数の型をとる関数をとっている。sortに>(大なり)など関数である演算子を入れるだけでうまくソートされる。右のコードは左と同じ処理であるが、lowerThanという関数を作り、何が行われているかをわかりやすく書いたものだ。関数を変数に代入し、関数の引数に渡していることがわかるだろう。

 佐野氏は「Objective-Cでは、関数・メソッド・ブロック・演算子は全て別のものだったが、Swiftでは全て関数で統一されている。ぜひ、mapやfilterを使いこなそう」と語る。

 ただし、mapする関数がOptionalを返す場合は二重に包まれてしまう。その際にはmap/flatMap を上手く使うとif letを多用せずに済み、構造として分かりやすくできる。

 そして三つ目のコツは「値型・不変性・プロトコル指向」である。まず、Swiftには2つの型があり、struct、enumで定義される型は値型、classで定義される型は参照型となる。Objective-Cではintなどのプリミティブ型、CGRectなどの構造体は値型となり、NSArray、NSStringなどオブジェクト型は参照型(ポイント)となる。一方、SwiftではInt、Array、Stringは全て値型であり、Objective-Cベースのクラスは参照型だ。

 また、Objective-Cではどんな変数でも再代入可能だった。しかし、Swiftの変数は、letでの宣言で不変、varで可変というように制約を持つ。この「不変な値型」は関数型言語と相性がいい。同じオブジェクトを別々に参照しているうちに勝手に書き換わりトラブルになることがよくあるが、しかし、不変な値型については参照の共有による副作用がない。つまり、変数を直接書き換えるのではなく、操作は全て「関数」で実現されるため、何が起きているか構造的に分かる。プログラミングを勉強し始めによく見る記述「a = a + 1」は、不変な値型の世界では使われないのだ。

 ここにSwiftでは「プロトコル指向」というパラダイムが持ち込まれている。それと対比する「クラス指向」が継承によってデータと機能が増えていくのに対し、「プロトコル指向」では具体型が必要最小のデータを持ち、プロトコルによって機能を足していく。

「プロトコル指向」というパラダイム
「プロトコル指向」というパラダイム

 「値型・不変性・プロトコル指向」について、佐野氏は「かちっとしたコードが書ける、というのでテンションが上がる。ただし、そうそうは甘くない」として、その理由を次のように述べる。

 「Foundation/UIKit は Objective-Cベースなので、クラスは参照型となり可変な値を持つ。さらにPure-SwiftなメソッドはSelectorで呼び出したりできないので、target-actionパターンと相容れない。さらに、Swiftのジェネリクスが未熟で、複雑な値型を作ろうとするとすぐ無理が出てくる」

 そこで、無駄な副作用のない設計を常に意識しつつ、そのために可読性を犠牲にしないことが大切だという。そしてSwiftがさらに進化し、UIフレームワーク自体がPure-Swift化されない限りは、「関数型プロトコル指向」を徹底するのは無理がある。「ほどほどに取り入れつつ、Scala、Haskellなどを学んで知見を広げよう」と佐野氏は語った。

 そして、Objective-CからSwiftに書き換える、ヤフーが作成したSwiftコンバータ「objc2swift」が簡単に紹介された。2015年末にオープンソースで公開されている。これからSwift対応したいと考えている人は試してみるとよいだろう。

 最後に佐野氏は「Objective-CからSwiftに移行することで、より効率的で安全なコードを書くことができる。そして、この先もAppleはSwiftを推進するのは明白なので、できるだけ早くキャッチアップしたい。ただし、大きなアプリをSwift対応するには、メリットとリスクを見極め、計画的に進めることが肝心。単にコードを書き換えるだけでなく Swiftらしい書き方を習得してメリットを最大化しよう」と結び、セッションを終えた。

お問い合わせ

 ヤフー株式会社



  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:【デブサミ2016】セッションレポート

もっと読む

著者プロフィール

  • CodeZine編集部(コードジンヘンシュウブ)

    CodeZineは、株式会社翔泳社が運営するソフトウェア開発者向けのWebメディアです。「デベロッパーの成長と課題解決に貢献するメディア」をコンセプトに、現場で役立つ最新情報を日々お届けします。

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5