Swift Playgroundsで学ぶiOSプログラミング

ファイルとして保存したオブジェクトを展開して元に戻す方法

文●柴田文彦 編集●吉田ヒロ

2018年03月05日 17時00分

日時を表すDateのオブジェクトを直接アーカイブ/アンアーカイブする

 前回のプロパティリストとは異なり、アーカイブ/アンアーカイブできるのは配列や辞書だけではありません。試しに日時を表すDateクラスのオブジェクトを直接アーカイブして保存し、また読み込んでアンアーカイブして元に戻してみましょう。

NSKeyedArchiverとNSKeyedUnarchiverの組み合わせでは、Dateオブジェクトも直接保存、再現が可能です。この例では、読み込んだデータが空の場合だけ現在日時をアーカイブして保存しています

 上の例とほとんど同じ構成のプログラムですが、今度は保存するのはDateオブジェクトです。Swiftでは、厳密にはDateはクラスではなく構造体ですが、SwiftからNSDateを使うためのブリッジとなっています。そのため、NSKeyedArchiverのようなObjective-CのAPIで利用する際には、NSDateクラスと同様に扱えるのです。

 このプログラムを動かすと、2回目以降は、その前に保存したDateオブジェクトをアンアーカイブします。プレイグラウンドのデバッグ機能によって、その日時をdescriptionメソッドによって文字列に変換したものを表示して確かめることができます。

ファイルから読み込んだデータが空でない場合には、読み込んだデータをDateオブジェクトに変換してから、Dateオブジェクト固有のメソッドを使っています

 言うまでもないことですが、アーカイブして保存したオブジェクトは、アンアーカイブすることで完全に元に戻るので、データだけでなく、そのメソッドも利用できるのです。

プログラムを最初に起動した日時と最後に起動した日時を1つの辞書として保存

 このあとで作るサンプルプログラムへの伏線として、もう少しだけ複雑なデータを扱ってみましょう。プログラムを最初に起動した日時と最後に起動した日時を1つの辞書に記録し、その辞書をアーカイブして保存します。その後、ファイルから読み込んでアンアーカイブした辞書の一部を変更してから、再びアーカイブ保存するというものです。まだ、ビューコントローラーは使わずに、デバッグ機能で動作を確かめられるようなプログラムです。

この例では、プログラムを最初に起動した日時と最後に起動した日時を、それぞ「first」「last」というキーで辞書に記録し、それをアーカイブして保存、再現する動作を確かめます

 プログラムを最初に起動した際には、その日時を「first」と「last」という2つのキーで辞書に記録してファイルに保存します。2回目以降は、そのファイルを読み込んでアンアーカイブしています。その後で、現在の日時を「last」のキーで辞書に上書きし、再びアーカイブしてファイルに保存します。そのため、起動するたびに「最後に起動した日時」の方だけが更新されていきます。

ファイルからデータを読み込んだあとで最後に起動した日時のオブジェクトについてだけ、辞書を更新してアーカイブして再びファイルに保存しています

 一方、「first」のキーで記録した方のデータは、プログラムを変更しない限り、最初に記録したものをずっと維持します。

DateComponentsFormatterを導入して過去から現在までの経過時間を見やすく

 上で示した最初に起動した日時と最後に起動した日時を記録するプログラムに手を加えていきます。日時の表示の、年、月、日、曜日、時、分、秒というかたちは絶対的なもので正確ではあるものの、ぱっと見ただけではそれがいつなのか実感しにくいものです。ましてや、その日時から今現在まで、どれくらいが経過しているのかは、指折り計算しないとわからないこともあります。

 そこで、プログラムによって、過去の日時から現在までの経過時間を計算して表示できるようにしてみましょう。そのためには、DateComponentsFormatterクラスが使えます。このクラスは文字どおり、日時を表すコンポーネント(月、日、時間、分、秒など)をフォーマットして文字列に変換するためのものです。さらに、2つの日時の差分を計算し、それを文字列として表現する機能も含まれているのです。

 その際の日時の差分の表現も、いろいろとカスタマイズが可能です。ここでは、常に2つの単位の組み合わせで表示するようにしてみます。つまり、分単位で表せる範囲では「何分何秒」で表示し、時間単位になれば「何時間何分」、日単位では「何日何時間」、そして月単位になれば「何ヶ月何日」のように表現するということです。人間の感覚としては、期間が長くなって日単位で表示しなければならない場合には、分や秒の数字は、ほとんど関心がなくなることが多いからです。

 プログラムの構造や、基本的な機能は上の例のものと同じです。そこにDateComponentsFormatterクラスのオブジェクトを使って、記録した日時から現在までの差分を文字列で表現するための機能を加えているだけです。

プログラムを起動した日時を記録して表示するだけでは以前に取り上げた例と大差ないので、今回は起動日時と現在との差を適当にフォーマットして表示できるようにします。そのためにDateComponentsFormatterクラスを利用します

 DateComponentsFormatterクラスのオブジェクのallowedUnitsプロパティによって表示に使う単位を月、日、時、分、秒に限定し、maximumUnitCountによって、表示する単位の数を2つに制限しています。

 このプログラムでは、表示はまだプレイグラウンドのデバッグ機能に頼っていますが、2つの単位を組み合わせた日時の差分の表示が実現できていることが確認できます。

日時を表示する単位を最大2つに制限しているので、1分以上の経過時間がある場合には、何分何秒で、1時間以上では何時間何分のように表示するための文字列が得られます

初回起動から最後に起動したときまでの経過時間を表示するアプリ

 今回の最後に、ここまでの成果をアプリ風のプログラムにまとめておきましょう。上の例で示した日時の差分を表現した文字列をラベルとしてビューの上に配置するものです。使っている機能や手法は、これまでに取り上げてきたものの組み合わせばかりなので、ざっと簡単な説明にとどめましょう。

 まずビューコントローラーのクラスを定義して、その中に4つのラベルを用意します。

今回のプログラムをアプリの形態で動かすために、UIViewControllerクラスを継承するArchivedViewControllerクラスを定義します

 4つのラベルには、順に「前回の起動からの経過時間」という固定の文字列、実際に前回の起動からの経過時間、「最初の起動からの経過時間」という固定の文字列、実際に最初の起動からの経過時間をそれぞれ表示します。これらのラベルにはviewDidLoadメソッドの中で必要な初期化処理を施しておきます。

viewDidLoadメソッドの中では、用意した4つのラベルを順に初期化しています。1番目と3番目のラベルには、固定の文字列を表示しますが、2番目と4番目には経過時間を表示するため、この段階ではまだ表示内容は設定していません

 このプログラムでは、基本的にviewDidLoadの中に、すべての機能を実装しているようなものです。上の例で示した日時オブジェクトの保存と再生、日時の差分の計算と文字列化の処理も、すべてviewDidLoadの中に書いています。そしてその結果を2番目と4番目のラベルのテキストとして代入します。

2番目と4番目に表示する内容には前の例のプログラムと同じようにして、プログラムを最後に起動してからと最初に起動してからの経過時間をフォーマットして表現した文字列を設定します

 最後に、4つのラベルをビューコントローラーのビューに張り付けるところまでがviewDidLoadの仕事です。あとは、ラベルのレイアウトのためにviewWillLayoutSubviewsメソッドを実装し、プログラムの末尾で、上で定義したビューコントローラーのオブジェクトを作成し、それをプレイグラウンドのライブビューに張り付けています。

ラベルの初期化がすべて済んだところで、ラベルを親のビューのサブビューとして設定します。また、viewWillLayoutSubviewsメソッドで、4つのラベルのレイアウトを決めています

 このプログラムは、時間を置いて何回か起動してみて、日時の差分の表示を確認してください。差分が1分未満のときは秒の単位だけ、それ以外の場合は適切な2つの単位を使って差分を表現できることが確認できるはずです。

プログラムは、ある程度時間を空けて何回か起動してみてください。そうすることで、2つの経過時間の意味と単位の表現の違いがよく現れるでしょう

次回の予定

 NSKeyedArchiverとNSKeyedUnarchiverを組み合わせて使えば、多種多様なオブジェクトを冷凍保存し、後から展開して、通常どおりに利用できることがわかりました。このような機能の応用例は、ほとんど無限に考えられるでしょう。実用的なiOSアプリの開発には、不可欠とも言えるツールになるはずです。このところ地味な内容が続いたので、次回は視覚に訴えるような効果を発揮する機能を取り上げる予定です。

mobileASCII.jp TOPページへ

mobile ASCII

Access Rankingアクセスランキング