Angularの周辺ツールについて調査してみた
周辺ツール(Node.js、Bower、Typings、Gulpなど)の背景、特徴を調査し、アウトプットする。
Node.js(サーバサイドJavaScript)
Node.jsとは
JavaScriptはブラウザ上だけではなく、サーバサイドでも動く。PHPやJavaなどと同じような使い方ができるということだ。
サーバサイドJavaScriptと呼ばれるが、その中でも代表的なのがNode.jsだ。現状は、他にそこまで有名なものもないので、「Node.js = サーバサイドJavaScript」だと認識しておけばいいだろう。
なぜサーバサイドでJavaScript?
これほど注目を浴びている理由を端的にお伝えしよう。
「クライアントもサーバサイドも同じ言語で書けたら楽じゃない?」
これが最大の理由だ。
近年、JavaScriptがWebの表舞台のど真ん中に立つようになった。Flashが姿を消し、パソコンの性能が年々上昇しているのがその理由だ。リッチなサイトやWebサービスがどんどん登場している。
サーバサイドがよくわからないWebデザイナーの人たちも、JavaScriptは触らざるを得なくなっており、「JavaScriptならやったことある!」という状態になっている。
だからこそ、サーバサイドプログラムもJavaScriptで書けると言われると、「なにそれ魅力的ですね」となり脚光を浴びているわけだ。
JavaScriptでサーバサイドもクライアントサイドも書けたら効率的だ。JavaScriptを書けるエンジニアだけを集めたらいい。
Node.jsの強み
下記2点で強みを持っている。
- リアルタイムな反応が必要なWebの分野
- 多数のアクセスがある場所
①リアルタイムな反応が必要なWebの分野
Facebookのメッセージ、Googleスプレッドシート、LINE、Twitter、instagram、snapchat、Paypalなどがリアルタイム性が高い例だ。
しかし、例えばLAMP開発環境(※1)でチャットアプリケーション開発することは、簡単ではない。
なぜなら、下記問題の為に、ユーザーがチャット画面を見るまでに必要以上の時間がかかってしまっていたからだ。
- webブラウザとWebサーバ側が常時接続すること
- データを保存し続け、Webブラウザ側に表示し続ける必要があること
しかし、Node.jsでは「新しい情報が来た!」と知らせてくれる機能を割と簡単に実装できる。お知らせが来たら、それを反映すればいい。チャットサービスなどがすんなりと作れるのだ。
※1 LAMP環境ってなに?Webサービスを作るための環境構築を理解しよう
②多数のアクセスがある場所
Node.jsの第一目標は、「スケーラブル(拡張可能)なネットワーク・プログラムを作成するための簡単な方法を提供すること」である。
JavaやPHPのようなプログラムでは、接続ごとに新しいスレッドが作られる。8GBのRAMで計算すると、最大ユーザー数は5000名以下しかアクセスができなくなる。これを増やそうと思ったら、コンピュータを増やすしかない。
Node.jsはこの問題を解決する数少ないプログラミング言語だ。シングルスレッドで非同期処理を行い、この問題に対応できる。
ただし、単純な処理以外にはそこまで強いイメージもない。一概に速度が速いとは言えないところがまた難しい。
Node.js上で動くフレームワーク5選
次にNode.js上に動くフレームワークについて紹介したい。
①AngularJS
AngularJSは、Googleとコミュニティによって開発されたMVCフレームワークです。双方向データバインディングという機能があり、モデルとinputフィールドをバインドすることによって、モデル変更やユーザー入力によるフィールド変更など双方向のデータバインディングが可能です。JavaScriptはもちろん、Node.jsでも使用出来ます。
②Backbone.js
Backbone.jsは、デザインパラダイムに基づいたJavaScriptのライブラリ兼フレームワークです。グローバル変数を排除したり、モデルの保持が可能です。
③Express
Expressは、軽量かつシンプルなフレームワークです。MEANスタック(MongoDB、Express、Angular、Node.jsの環境)でも使用されており、Node.jsをあまり隠さず使用するフレームワークとして有名です。
④Sails
Sailsは、Express をベースにRubyのフレームワークであるRailsライクな、フルスタックフレームワークです。短期間で開発しなければいけないような場合に、威力を最大限に出来るフレームワークです。
⑤Meteor
Meteorは、1画面において複数の処理を行うアプリであるSPA向けのフルスタックフレームワークです。リアクティブアプリケーションを少ないコードで構築することが可能です。
Typings(TypeScript型定義管理ツール)
TypeScriptの型定義ファイルを管理するツールです。
以前(2016年1月頃まで)は、tsdが台頭していたみたいでしたが、 tsdが非推奨となったため typingsを使用する人が増えました。
GitHubから型定義を取得してくるしかなかったtsdと違って、npmやbower、githubプロジェクト、ローカルファイルシステムやhttp経由で型定義ファイルを取ってこれるのが特長です。DefinitelyTypedもサポートしているので、tsdから移行して困ることはありません。
Bower(依存性管理/パッケージマネージャー)
Twitter社が作ったフロントエンド用のパッケージマネージャです。 Java で言う Maven、 Ruby で言う gem、 Perl で言う cpan のようなものです。 Node.jsには npm と呼ばれるパッケージマネージャがありますが、それに強く影響を受けています。
パッケージマネージャを利用することでライブラリを自分で管理する必要がなくなり、管理するファイルの数を減らすことができます。 また、パッケージマネージャを利用することでライブラリのバージョン管理をしやすくなります。
具体的には、各パッケージにある設定ファイル"bower.json"に依存パッケージが記述されており、インストール時に依存パッケージを含めて読み込む仕組みとなっています。
Grunt(ビルドツール/タスクランナー)・・・番外編
⇒シリーズ化されている
Gruntとは、自動化のためのビルドツール(タスクランナー)です。 (Ant,Maven,Gradleのようなもの。) Node.jsを使用し、ビルド用のスクリプト(Gruntfile.js)をJavaScriptで記述してタスクを定義します。 また、「プラグインモジュール」を使用して、タスクを独自に定義でき、任意の処理を行えます。
Node.js上で動作しているため、Webサーバーを使用することやライブラリロード(ファイル更新を検知して任意のタスクを実行)も可能です。
BowerとGruntの違い
GruntはSass(cssのプログラムっぽくしたもの)やCoffeeScript、TypeScriptのコンパイルやテスト実行などのタスクを自動化してくれるツールで、BowerはCSS/JavaScriptのパッケージ管理ツールです。
Bowerは指定したバージョンのパッケージのダウンロードまではやってくれるけれど、GitHubのリポジトリ毎ダウンロードされるものもあるようで、必要なファイルの抽出とかまではやってくれない。そこで、GruntのタスクでBowerの実行からファイルの抽出までを自動化してているのが下記のページ。
GruntとBowerを使ってWeb開発用のテンプレートを作成する
さらに、Yeomanという快適な開発ワークフローを提供してくれるツールもあります。
Yeomanとは、公式サイトいわく、「The web's scaffolding tool for modern webapps」(「今風のWebアプリのための土台/基盤を作ってくれるツール」)とのことです。
Yeomanを使うと、近ごろ複雑化しつつあるさまざまなフロントエンドプロジェクトのひな型を、対話形式のコマンドで簡単に生成できます。
またYeomanは、「Grunt」「Bower」「Yo」の、3つの要素から構成されています。「Yo」とはプロジェクトのひな型生成ツール、「Bower」はフロントエンドライブラリの依存性管理ツール、「Grunt」はビルドツールです。これら3つのツールを統合して、一連のワークフローを提供するのがYeomanです。
Gulp(ビルドシステムヘルパー)
gulpはNode.jsをベースとしたビルドシステムヘルパーです。Gruntと似た目的を持って作られたツールで、gulpを使えばさまざまな作業を自動化することができます。gulpの一番の特徴はサイトのトップページで「ストリーミングビルドシステム」と自ら名乗っているように、ファイルの処理をストリームで行うというところです。この特徴によって複雑なタスクも細かくカスタマイズして書くことができます。
ビルドシステムヘルパーとタスクランナーの違い
先に登場したタスクランナーのGrunt、ビルドシステムヘルパーのgulp、両者の目的は似ています。どちらも、いろいろな機能(プラグイン)を使い、目的とする成果物を求める一連の処理(タスク)を実行しますが、そのアプローチは少々異なります。
Gruntの場合、タスク=プラグインといった感じに、その単一のタスク(プラグイン)を実行させるのが主な役割です。単一のタスクをうまいこと組み合わせて実行することで、ビルドという大きい目標に辿り着くというアプローチです。
gulpの場合、プラグインはあくまでも入力に対して処理を行うためのものです。gulpのタスクはGruntでいうところのビルドに近いものです。タスクの中でいろいろなプラグインを組み合わせることで、タスク=ビルドを行うといったアプローチを取っています。プラグインを容易に組み合わせられるので、柔軟なタスクを作成できるとともに、タスク同士の依存関係を極力減らすことが可能です。
ストリームによる処理の利点
gulpはファイルをストリームとして扱いながら処理を行います。
ファイルに対してコンパイル>プレフィックス付与>圧縮と、流れるように処理を行い、最後にファイルを書き出します。
次の処理へ次の処理へと渡すので複数の処理を簡潔にまとめることが可能で、I/Oによる不要な待ち時間が発生しないのも強みです。
手続き的な記述と宣言的な記述の違い
GruntではタスクをJSON形式で宣言的に記述していきます。宣言的な記述はタスクの内容がパッと見でわかりやすい反面、タスク同士を組み合わせるのが難しいです。タスクが増えていくと、それぞれの関連性などを把握しきれなくなります。
一方、gulpでは処理したファイルをストリームによって次の処理に渡すことで、手続き的に記述することができます。「アレをしてからコレをする」というタスクをわかりやすく、より簡潔に書くことができます。gulpのAPIはたいていコールバック関数を取れるようになっているので、タスク実行後に何かする、といったものもわかりやすく書くことができます。gulpではタスクと処理を行う機能とが分離できることで、タスクの持っている役割をより明確にすることができます。
Webpack
Browserify
Bootstrap
Yeoman
Laravel
Mocha
AngularJSの背景を調査してみた
きっかけは、AngularJSの存在を知り、そうすると芋づる式に知らない単語がたくさん出てきて
そもそもJSってなに?なにが目的で生まれて、他のフレームワークと何が違うの?JS使うには他に何が必要なの?
・・・整理したい!!!!
ということから調査結果をoutputしようと思う。
JSの変遷
CommonJS、ES6、Node.js、Webpack、Browserify...etc JSの勉強してると、登場する単語が多すぎて、どうも全体像がつかめない。 そして勉強していくにつれて、「これ前提知らないと分からないっしょ...」みたいなことが多数出てきたので、その前提を色々とまとめてみることにした。
Angularの変遷
AngularJS
- 2012年6月にリリース
- 周辺ツールが多い!(Gulp, Bower, Grunt)とか。でもここら辺の勢いは最近あまりないし、独特の書き方がほかに応用できない。
※ Gulp,Grunt・・・タスクランナー(実際にブラウザで使えるまでの諸々の作業を自動化してくれるツール)
bower・・・パッケージのバージョン管理
Angular2
- 2016年9月16日にリリース
- 周辺ツールはAngularCLIが使えればOK。
- 1→2で結構文法が変わって、互換性もない(重要)
AngularCLI・・・公式コマンドラインツール
Angular4
- 2017年3月にリリース
- 周辺ツールはAngularCLIを使えばOK、今後半年ごとにメジャーアップデートされるときにも一緒に進化してくれる予定。
- 2→4で文法が少し変わった。でも互換性あり! 参考書にAnguar2のやつを使っていてもとりあえずは大丈夫
Angular5
- 2017年11月にリリース
- 次バージョンとなるAngular 5のテーマの1つはシンプリシティ。 その1つは、Angularアプリケーションのコンパイルをよりシンプルにする。JITコンパイラだけでなくAHTコンパイラ(A head of time:事前コンパイラ)を採用したが、この2つがあると混乱することもある。今後はAHTコンパイラをデフォルトにすることでビルドの手順を一本化し、余計な作業を減らしていくつもりだ。
- もう1つはスピードとサイズへの注力。MaterialやIonicを利用したときなどでも最適に扱えるようにする。
- 最後の1つは、スムーズなアップデートだ。バージョン4のときにもこれを約束したが、将来のバージョンに渡ってもすすめていく。
ところでAngularJSからAngular2になって何が変わったの?
AngularJSはいいjsフレームワークだったが、問題点整理をすると「重い」とか「記述ルールがややこしい」とかいろいろでてきたらしく、「それだったら、その問題点をがさっと整理し直して後継バージョンを出すぞ!」と気合の入った当プロジェクト。 気合が入りすぎて、互換性はほとんどない。 関連記事はこちら。
AngularJS と Angular2 の連携:シームレスなアップグレードの方法について
AngularJSで書いた資産をAngular2で使うのは無理だろうけど、Angular2は便利だから、混在させることができるよ!と書いている。
しかし、AngularJSと比べて「処理速度は3〜5倍」「inputとoutputに分かれて書きやすくなった」「TypeScriptを推奨しているので、コードの保守性が圧倒的に優れてる(どっちかというとTypeScriptの成果ですが)」などなどあるので、これからjsフレームワークの採用を決めるなら有力候補の一角になるだろう。
ところでAngular2からAngular4になって何が変わったの?
- 色々なコンパイルをするタイミングを変えたので、アップロードされるファイルサイズが小さくなった(30%~50%減)
- タグがタグに変更(互換性あり)
- コンポーネントをもう少し細分化
- @angular/animationってのが追加された、アニメーション使っていた人は注意。使い方は変わっていない
- AngularCLIのインストールが変更(重要)
JSフレームワークの独自進化について考える
1. jsが有効化されているのが当たり前の時代になった
2. W3Cの拡張空間を仮想DOMによってjsフレームワークが作ろうとしている
の二点が結構はっきりしてきたように感じる。
「jsが無効化されてても操作できるようにしなさい」というのは一時代前のお作法だった。 しかし、ガラケーが減り、スマホが当たり前になって、IEのシェアが落ちていく中で、この作法は当たり前ではなくなり、「jsは有効化されてて当たり前」に入ったからこそ、jsフレームワークでviewを構築するような時代に入ったことを感じる。 今では、「jsが有効化されているのが当たり前の時代になった」ことを多くのエンジニアが実感しているであろう。
もうひとつの「W3Cの拡張空間を仮想DOMによってjsフレームワークが作ろうとしている」はかなり大切な局面だと思っていて、ブラウザ間差異はjsフレームワークで吸収する前提のもと、これからもどんどんとjsフレームワークが独自進化を遂げていくのではないか。 つまり、jsフレームワークが進化していくことにより、W3Cで勧告されるような機能を意識しなくても使用しなくてもよくなるとなるというのは、大きな時代の変化ではないか。 この変化を象徴しているのが、まさにAngular1からAngular2への変化かと思っている。
調査メモ
JSについて
JavaScript界隈の流行の変遷を調査する時は「npm trends」がオススメ ⇒トレンド系を調査するのは何が良いのか?
フロントエンド+JavaScriptの歴史(1) #JavaScript
Angularについて
AngularJSをこれからはじめてみようかな?という人のための記事まとめ
AngularJSとAngular2の比較から、jsフレームワークの独自進化を考える
下記についてまとめるのも楽しいかも。 (詳細や他との比較は次回記載)
Node.js Bower Typings Gulp
フレームワーク構築入門研修の参加報告
はじめに
研修に参加してきたので、忘れないように自分用にoutputしておく。
カリキュラム内容
コース概要
JavaによるWebアプリケーションアーキテクチャを設計する際によく利用されるデザインパターンについて学習し、その実装方法について学習していきます。 講義で採り上げるパターンはシステム開発でよく利用されるMV*やIoC、サービスクラス、DAOなどです。本コースで学んだアーキテクチャに関する知識は既存のフレームワークを理解するのにも役立つ知識ですので、アーキテクチャ設計を一から行わない方にもお勧めのコースになっています。
学習目標
- レイヤ化されたWebアプリケーションの構成を理解する
- 学習した各パターンの意義と使いどころを理解する
- Webアプリケーションのアーキテクチャを構築する際の選択肢を持つ
学習内容
フレームワークとは
- Inversion of Control
プレゼンテーションレイヤに関するパターン
- MV*
ドメインレイヤに関するパターン
- サービスクラス
データソースレイヤに関するパターン
- DAOパターン
-
- 動的なクラスやメソッドの利用
- アノテーションの実装と利用
-
- 依存性の解決(ファクトリー、DI、AOPの実装)
- 汎用的なDAOの実装
1. 基本の考え方(デザインパターン)
デザインパターンとは、オブジェクト思考に基づいて経験則から得られた、プログラミングにおける優良なパターンのこと。 GoF本では23個が提示されている。
その中で、代表的な4つについて学習した。
①Template Methodパターン
目的:具体的な処理をサブクラスに任せる
スーパークラスでは処理の順番だけが決められ、サブクラスでは具体的な処理が実装されている。
※スーパークラスにテンプレートを記載する、という意味合いからメソッド名が付けられた。
②Factory Methodパターン
目的:インスタンス作成をサブクラスに任せる
抽象度を高めることで、可用性を高めることができる。 しかし、ファクトリを指定する手段を別途考えなくてはならない。 →DIで解決する。
③Singletonパターン
目的:たった1つのインスタンス
<他の言語の例>
scalaだと、
「object ○○」でシングルトンとして使用可能。
⇨自分たちで作成しようとしないこと
④Strategyパターン
Strategyとは処理内容(=戦略)の意味。
2. プレゼンテーションレイヤに関するパターン
MVC(Model-View-Controller)
MVCとは、ユーザインターフェースの動作を3つの明確な役割へ分割するアーキテクチャパターン。
- View・・・プレゼンテーションレイヤ(変わりやすい)
- Controller・・・プレゼンテーションレイヤ(変わりやすい)
- Model・・・ドメインレイヤ、データソースレイヤ(変わりにくい)
その他、MVP、MVVM、MVWなど多数あるが、どの機能をどこに実装するかは設計者によって様々である。 ただ1つ言えるのは、変わりやすいものと変わりにくいもので分けている、ということだ。 例)Angularでは、MVW(W:Whatever)を使用している。
<参考>
参考ではあるが、インタラクティブさや使いやすさ向上などのために、JSが多様化されたものが増えてきた。その例がGoogleマップである。
DOM操作を使用し、ページ全体ではなくその一部分を細く書き換えるような動作を行うものだ。これらの構造を作成するためのフレームワークとしてBackbone.jsやAngular.jsが挙げられる。
これらはサーバ上の動作処理と同じかそれ以上をクライアント側でも複雑な処理を記述する必要がある。
そのため、サーバ側でもクライアント側でもMVCモデルを使用することで。複雑さへの対応を取ることが求められつつある。
しかしそれだとクライアントもサーバもModelが配置され、冗長的なので、サーバ側もJSで作成しようという動きが出てきた。その中で出てきたのがサーバサイドJSとしてのnode.jsである。
※これについては後日調べてoutput
Front Controller
Front Controllerとは、すべてのリクエストを受け付けるコントローラを1つだけ用意するアーキテクチャパターン。
例えば、設計上の課題として共通の処理だけど本質的ではない部分(前処理や後処理)を各サーブレットに実装しなければならない場合に、これらの部分を個別にサーブレット内に実装するのは明らかに無駄が多い。このような共通処理を実装するにはどうすればよいかの解決策として、Front Controllerパターンがある。
その際、Front Controllerにはアクションクラスにリクエストを振り分ける何らかのルールを与える必要がある。その設定方法としては、設定ファイルを用意したり、ロジックとしてif-else文で作り込んだり、アノテーションによって記述したり、などの方法がある。
設定ファイルにリクエストとActionの関係が書かれていくとxmlが大きくなる「xml地獄」が起こる。そのため、xmlを小さくしようというのがトレンドである。
※設定ファイルのトレンドについては次の機会に調べてoutput
Template View
HTMLページに特殊なタグを埋め込むことで、動的な情報を表示するテンプレートとする。(要はJSPのこと)
問題点に対して純粋な(特殊なタグを全く入れない)HTMLをテンプレートとして使用するプロダクトも存在している。(例:Thymeleaf)
※これについては後日調べてoutput
3.ドメインレイヤに関するパターン
サービスレイヤ
プレゼンテーションレイヤとの境界に位置し、ドメインレイヤに対する処理を受け付ける役割。 導入を検討するのは、複数のDBテーブルを使ってのトランザクション処理が必要な場合など。
トランザクションスクリプト
実際にビジネスにおいて行われる手続きをそのままプログラムロジックとして記述するパターン
ドメインモデル
その業務(ドメイン)における処理内容と処理するデータを一体化させたモデル
トランザクションスクリプトとドメインモデルのどちらを使用するかは、システムの難易度によって変わる。JavaによるWebアプリケーションはトランザクションスクリプトを使うことが多い。
なぜトランザクションスクリプトが多く使われるのかというと、トランザクションスクリプトは昔ながらの手続き指向に近いからだ。そのため、DB内のデータも素直に処理することができる。またドメインモデルだと、ドメインモデルとDBテーブル間で、モデルの表現の違いを変換する何らかの仕組み(※1)が必要だからだ。
※1 OR Mapper(Object RDB)
ドメインモデルによるシステム開発は、ドメイン駆動設計がある。
顧客と対話しながら、業務領域(ドメイン)を表すモデルを中心としてシステムを構築していく考え方のことだ。
例)顧客が本当に欲しかったもの(風刺画)
DI(Dependency Injection)
オブジェクトの注入のこと。
近年多くの業務システムは多層的な構造になっており、コンポーネントが他のコンポーネントに数珠つなぎのように依存した構成になっている。
これではコンポーネント単独ではテストできないし、再利用性も低い。→品質向上と開発の効率化が行いにくい
もっと依存性を低くしようということより、生まれた。
AOP(Aspect Oriented Programming)
アスペクト指向プログラミング
重複・横断的な処理を画一的に外部から介入し処理を行う。(処理そのものを介入する。)
例)ログ出力、トランザクション制御、セキュリティ、例外ハンドリング
4. データソースレイヤに関するパターン
Data Access Object(DAO)
DBアクセスをビジネスロジックから切り離す
Data Transfer Objet(DTO)
データを保持し他レイヤに運搬することを目的とするオブジェクト
O/Rマッピング
メモリ内のオブジェクトとRDBテーブルを相互に変換する仕組み
例)OR Mapper(Object RDB)
- Hibernate・・・難易度高め。独自のHQLを使用。
- mybatis・・・簡易的。SQLを重視したい場合に人気。
- JPA(Java Persistence API)・・・背後にHibernateが実装してあり、使いやすくするためにIFを定めている
- Doma・・・Hibernateやmybatisのいいとこどり。seasarのサポートは切れているが、依存していないので使用可能。おすすめ。
※ Domaについては今後調査する
5. フレームワーク構築時に使用するJavaテクニック
Javaリフレクション
アノテーション
SwiftのOptional型を勉強してみた
Optional型とは
Optional型の宣言方法
var a: Int? // Optional型 var b: Int // 非Optional型 var c: String! // Optional型 var d: String // 非Optional型
Optional型とImplicitly Unwrapped Optional型
型 | 宣言方法 | 型の実体 | アンラップ時の操作 |
---|---|---|---|
Optional型 | var a: T? | Optional\ |
明示的な操作が必要 |
Implicitly Unwrapped Optional型 | var a: T! | ImplicitlyUnwrappedOptional\ |
不要(暗黙的にアンラップされる |
ラップ(wrap)とアンラップ(unwrap)
Optional型(Optional\
Optional型(Optional\
Optional型の変数をアンラップする方法
1. Forced Unwrapping(!使用)
以下のように、!を使ってアンラップすることを「Forced Unwrapping」と言う。
class Dog { func bark() -> String { return "Wan!" } } var d: Dog? = Dog() // Optional型 print(d!.bark()) // -> Wan!
2. Optional Chaining(?使用)
以下のように、!ではなく?を使ってアンラップすることを「Optional Chaining」と言う。
class Dog { func bark() -> String { return "Wan!" } } var d: Dog? = Dog() // Optional型 print(d?.bark()) // -> Wan!
3. Optional Binding(if let, guard let使用)
if文やguard文の条件式で宣言され、Optional型の変数を代入された変数は、非Optional型になる。これを「Optional Binding」と言う。
class Dog { func bark() -> String { return "Wan!" } } var d: Dog? = Dog() // Optional型 // if letでアンラップ if let unwrappedDog2 = wrappedDog { print(unwrappedDog2.bark()) // -> Wan! } // guard letでアンラップ guard let unwrappedDog2 = wrappedDog else{ return } print(unwrappedDog2.bark()) // -> Wan! }
<参考>guard文を使用する目的
- 条件に合わない場合に処理を抜けるコードをシンプルに記述することができる。
- guard文ではelseブロックを抜けたあとでも変数を利用できる。
if文の場合は、if-elseブロックを抜けると条件式で代入した変数は使えなくなる。
4. Implicitly Unwrapped Optional型(暗黙的アンラップ)
Optional型ではなく、Implicitly Unwrapped Optional型を使うと、暗黙的にアンラップすることができる。変数をImplicitly Unwrapped Optional型で宣言する際には、?ではなく、!を使う。
class Dog { func bark() -> String { return "Wan!" } } // 「?」ではなく、「!」を使って宣言する var d: Dog! = Dog() // Implicitly Unwrapped Optional型 // アンラップ操作は不要(暗黙的にアンラップされる) print(d.bark()) // -> Wan!
nilに対して、アンラップをした場合の挙動
Optional型の場合
アンラップの方法 | 結果 |
---|---|
Forced Unwrappingの場合(!を使う方法) | ランタイムエラーが発生する |
Optional Chainingの場合(?を使う方法) | nilが返ってくる |
class Dog { func bark() -> String { return "Wan!" } } var d: Dog? = nil // Optional型 // Forced Unwrappingの場合(!を使う場合) print(d!.bark()) // ランタイムエラーが発生する: fatal error: Can't unwrap Optional.None // Optional Chainingの場合(?を使う場合) print(d?.bark()) // -> nil
Implicitly Unwrapped Optional型の場合
アンラップの方法 | 結果 |
---|---|
暗黙的にアンラップされる | ランタイムエラーが発生する |
class Dog { func bark() -> String { return "Wan!" } } var d: Dog! = nil // Implicitly Unwrapped Optional型 print(d.bark()) // ランタイムエラーが発生する: fatal error: Can't unwrap Optional.None
演算子を用いたアンラップ
nil結合演算子
??という演算子を使うと、オプショナル型がnilでなければその値を、nilの場合は指定した値を与えることができる。
var a: Int? let b = a ?? 10 // aはnilなので、10が代入される var s: String? = "Hello" println(s ?? "Bye") // sはnilでないので、その値(Hello)が出力される
nil合体演算子
以下のように、通常のif-let文や三項演算子より手軽に記述することができる。
通常のif-let文
var opv: String? = nil let S = "なにか" if let o = opv { print(o) } else { print(S) }
三項演算子
print((opv != nil) ? opv! : S)
nil合体演算子
print(opv ?? S)
nil合体演算子2つ以上に重ねることができる
let x: Int? = nil, y: Int? = nil, z: Int? = 3 let val = x ?? y ?? z ?? 0 print(val)
ハマったポイント
データクラス
//Infoクラス class Info { var price:Int? var reqDnb:RegDnb? } //Infoに含まれる電文クラス class RegDnb { var cardNum:Int? }
失敗例
データのクラスにnilが入っていたら、データに値を入れてもnilとなってしまう。
let info = Info() //info.reqDnb.cardNum = 12 // -> reqDnbをアンラップしろと怒られる info.reqDnb?.cardNum = 12 print(info.reqDnb?.cardNum) // -> nil(理由:reqDnbがnilとなるから) //アンラップ処理 if let unwrapCardNum = info.reqDnb?.cardNum { print(unwrapCardNum) } else { print("nilです") // -> nilです }
成功例
直属のデータクラスをインスタンス化し、値を挿入した。
let reqDnb = RegDnb() // -> ReqDnb reqDnb.cardNum = 12 print(reqDnb.cardNum) // -> Optional(12) //アンラップ処理 if let unwrapCardNum = reqDnb.cardNum { print(unwrapCardNum) // -> 12 } else { print("nilです") }
応用編
- map、クロージャなどを使用した記載