Page icon

第288回

2023/08/21
Empty
番外編
Empty
Empty
Empty
Empty
Empty
12 more properties
今回も引き続き、
UIKit
 にまつわるチップス集的な技術ブログと思われる「同じような処理だけどこっちの方がいいよってやつ」を眺めていきます。その中の 
数字の文字列変換とか
あたりがもう少し機になるところなので、前回に引き続いてそれを見ていこうと思います。よろしくお願いしますね。
——————————————————————————————————————————— 熊谷さんのやさしい Swift 勉強会 #288
00:00 開始 00:41 タイトルの語感が気になるような 01:09 標準でいろいろなフォーマッターが用意されている 02:28 DateIntervalFormatter は日付の範囲を表現 05:35 時間の経過を表現するなら DateComponentFormatter 08:57 思ったような変換がされない気がする 12:14 残り何日 — みたいな表記が簡単になるかも? 13:01 RelativeDateTimeFormatter は日付を相対表示が可能 13:34 DateInterval という表現 16:00 独自の型でもフォーマッターを導入すると良いのかもしれない 18:35 Formatter プロトコルがある 19:21 DateInterval 型を使ってみる 21:00 日付間のさまざまな関係を扱える 22:38 基礎的な文字列変換 23:06 変換イニシャライザーで変換する 26:11 String(format:) による文字列変換 27:14 標準機能を使った進数表記 29:53 今回の所感とクロージング ———————————————————————————————————————————
Transcription & Summarize : 熊谷さんのやさしい Swift 勉強会 #288
では始めていきますね。今日は「同じような処理だけどこちらのほうが良い」というブログについて解説します。この中ではUIキットに着目したTIPS集のようです。ただ、読んでみるとUIキットを使ったiOSアプリ開発のTIPS集といった内容に見えます。このブログは「のぴぃ」さんのもので、毎回こういったタイトルが取り上げられて読まれます。もう少し柔らかく、一般向けの言葉を選んだほうが良いイメージになるかなと思います。個人的にはそちらのほうがお勧めです。
前回も見た内容ですが、通知の文字列変換についてですね。
NSFormatter
が紹介されていて、詳しい方法はそのブログを見てもらう形です。このブログの中ではさまざまなフォーマッターが紹介されていますが、あまり注意されていなかったようです。例えば、
DateFormatter
DateComponentsFormatter
RelativeDateTimeFormatter
などですね。それらがどういったものなのかを見ていきましょう。
前回「デートインターバルフォーマッター」というものを見ましたが、これがとても便利そうだと思ったので紹介しますね。まず、この辺りをプレイグラウンドで見ていこうと思います。
DateIntervalFormatter
について確認していきましょう。
let formatter = DateIntervalFormatter() formatter.locale = Locale(identifier: "ja_JP") formatter.dateStyle = .short formatter.timeStyle = .none let startDate = Date(timeIntervalSince1970: 0) let endDate = Date() let dateString = formatter.string(from: startDate, to: endDate) print(dateString)
これで得られる結果は、「1970年1月1日から今日まで」といった範囲が表示されます。期待したとおり、
DateIntervalFormatter
は日付の範囲を表現するフォーマッターです。ロケールを日本に設定すると、日本の一般的な範囲表現になります。非常に便利ですね。
次に、
DateComponentsFormatter
について見ていきましょう。これは時間の差分を表現するフォーマッターです。例えば、1970年から現在までの経過時間をフォーマットします。
let componentsFormatter = DateComponentsFormatter() componentsFormatter.unitsStyle = .full componentsFormatter.calendar = Calendar(identifier: .gregorian) componentsFormatter.allowedUnits = [.year, .month, .day] let startDate = Date(timeIntervalSince1970: 0) let endDate = Date() let durationString = componentsFormatter.string(from: startDate, to: endDate) print(durationString ?? "No result")
これにより、「53年」といった結果を得ることができます。
DateComponentsFormatter
はデータの差分を表現するもので、特に時間経過を表示する際にとても有用です。例えば、カレンダーアプリなどで非常に役立つことでしょう。
最後に、カレンダーを日本のロケールに設定する方法も紹介しますね。
let calendar = Calendar(identifier: .gregorian) calendar.locale = Locale(identifier: "ja_JP") let componentsFormatter = DateComponentsFormatter() componentsFormatter.calendar = calendar componentsFormatter.unitsStyle = .full componentsFormatter.allowedUnits = [.year, .month, .day] let startDate = Date(timeIntervalSince1970: 0) let endDate = Date() let durationString = componentsFormatter.string(from: startDate, to: endDate) print(durationString ?? "No result")
こうすることで、日本のロケールに合わせたカレンダー表現が可能になります。コードの整備をしながら進めていくと、より使いやすいアプリケーションが作れるようになりますね。
今回はここまでです。次回も引き続き、Swift言語について学んでいきましょう。 なんだこれは、日付が日本語になった。これはいいのかな? これ、バグなのかな? 念のため、日本語になりそうなものですけどね。どうするんだろう、これ。
unitStyle
イコール。この辺、何が変わってくるか名前からわからないですね。
ショートだと日本語になった、これかショート。まあいいか。ほら、だから1970年1月1日から53年7ヶ月2週間とか、こんなふうに出てくる。これ、なかなかいいですね。ここで
unitStyle
を今やったら、アロードユニットスタート。これで制限できるんですよ。たとえば年齢を知りたい場合、こうすると53年が入ります。なるほど、もう少し細かく出てほしい気がしますけどね。これは、うーん、いいのかな。
まあいいか。これを
second
とかにすると、こんな感じですよ。「何秒経過した」みたいなね。他に何だろう、ミリ秒とかはないと。
second
か、うーん、そうか、オーバーフローしたかな。エラーになったね。とりあえず、
second
秒までか、ちょっと足んないですね。もう1レベル、ミリ秒レベルまでいってほしい気がするけど。規模が小さくて、スケールが大きくてダメそうですね。
unitCount
イントロ最大数、
time unit
。これは何だろう、ポール153ね。これは何をするといいんだろう。アナウンスとかするとどうなんだろう。643個です。バカだからちゃんと調べないとダメですね。
formatting behavior
、面白い。ゼロのときのフォーマッターもあるんだそういえば。ありますね、何かとね。
allowsFractionalUnits
、小数部分と整数部分ですね。整数の最大値と最大カウント1。設定の2513。ちょっとイメージと違う、もっと小数点が出そうな気がする。これ、ショートなのが良くないのかな。見本とじゃなくて、実証なる。この辺も分かんないね、調べればね。ポケモンと調べればちゃんと書いてあると思うんですけど。
これを1100とかにするとどうなるんだろう。分かんないね。まあいいや。
fractionalUnits
これをスタンドトゥルーグループ? 何だこれ。グーリオンかイメージとか。
true
にするとどうなの? 小数点するのあんまりね、どうかな。まあいいや。細かいところは興味ある人が頑張って調べてもらえればオッケーとして。
とりあえずこんな感じでね。バックがあるから、何だ定理まであと何日みたいなね。そういったのが簡単に表示できる。国に応じてね、多分国によって表現の仕方が変わってくるかと思うんで、これ主にローカライズの時にこういったフォーマッターは便利ですね。ローカライズしなくても、細かいこと考えなくていいし、バグも見にくいしね、いいですけどね。
まあ、そんな感じで面白そうなフォーマッターがいろいろあって、良いなと思ったんですけど。なんかブログに書いてあった
relativeDateTimeFormatter
って何なんだろう。相対的な日付か、昨日、明日、そういうやつか。ネームズにすることで、これね、便利な時とそうじゃない時とありますけど。まあまあ、そういったのが他国の表現でできるのはいいですね。こんなふうにフォーマッターがいろいろあって面白いなという感じですが。
これを見ててね、面白いと思ったんですけど、この
DateIntervalFormatter
。こっちは日の範囲を表現するやつですね。これロケールを変わってるね。ロケール間違ったか。カレンダーってダメなのかな? ロケールに入れないとダメなのか。カレンダーのロケール入れてあげると、これすると日本の表記になりますね。これショートだから、ミドルとかミディアムカットとかにすると、もうちょっとミディアムとか。ロングかな? にすると日本っぽく。あれ、何なんだ。ロングじゃない、フル。でもこれは日本語表記になった気がするけどね。まあいいや。細かいカットを開いておいて。
こういうふうに簡易表現できますけど、この
DateIntervalFormatter
が何か扱えるものとして、フォーマッターストリングフロム。そうだ、これデートインターバル型っていうのがある。タイムインターバルはよく使うんですけど、デートインターバルっていうのがあって、これを見ると二つの日付を取れる。スタートとエンド、あとデュレーションっていうインターバルトレビューンになってて、プロトコル的にはブチブチブリッジと比較。そのところか。収穫取れないのかな。とりあえず二つの日付範囲を表現するかっていうのがあったのね。知らなかったけど。これでやってみるか。いや、ここまできた。エクステンションデータインターバルで、デートインターバルでストリング表現ができるよっていうエクステンションと、あそこまでか。まあいいか。 で話を戻していきたいと思います。
今回は、イニシャライズやスタート、エンド、デュレーションを扱う方法について話しましたが、フォーマッターを使うことで表現の幅が広がりますね。はっきりとした数値ではなく、おおよその日数を表示したいという場合などに役立ちます。こうしたフォーマッターの役割を考えると、型そのものに組み込むのではなく、適切なフォーマッターを作成して使うと良いでしょう。
例えば、カスタムな文字列変換を行いたい場合、その場でヒューマンリーダブルな表現を直接埋め込むのではなく、フォーマッターを作成して対応します。これにより、その表現方法が使いたい時に再利用できるようになります。
データを表現する際に、フォーマッターから探す癖をつけると良いかもしれませんね。「マイバリュー型に対してのフォーマッター」を構築すると、データを直接扱うのではなく、フォーマットを通じて扱うことができて便利です。プロトコル指向で設計すると、型が直接持つのではなく、フォーマッターを使って柔軟な表現が可能になります。
DateIntervalFormatter
を使うと、
DateInterval
型が持つプロパティの表示をカスタマイズできます。例えば、スタート日付と終了日付の範囲をフォーマットし、このインスタンスをヒューマンリーダブルなテキストとして出力できるようになります。
次にデータインターバル型 (
DateInterval
) について話します。これを使えば、たとえば
時刻A
から
時刻B
までの範囲を表現できます。この型にはスタート日時、エンド日時、そしてデュレーションのプロパティがあり、さらにその範囲に任意の日時が含まれているかを確認できる
contains
メソッドもあります。
具体的には、以下のように使います。
let startDate = Date() let endDate = Date().addingTimeInterval(3600) // 1時間後 let dateInterval = DateInterval(start: startDate, end: endDate)
これにより、指定した時刻の範囲を持つインスタンスが作成できます。このインスタンスを使って以下のようにプロパティにアクセスできます。
let start = dateInterval.start let end = dateInterval.end let duration = dateInterval.duration
また、現在の時刻がこの範囲内に含まれているかを確認する場合は
contains
メソッドを使います。
let now = Date() if dateInterval.contains(now) { print("現在の時刻は範囲内です") } else { print("現在の時刻は範囲外です") }
このようにして、日付の範囲を持つデータを扱うことができるのは非常に便利です。頭の片隅に入れておくと良いですね。
いろいろ見てきましたが、元のブログに戻ります。数字の文字列変換に関しても、フォーマッターが標準で提供されていますが、ローレベルな数字の文字列変換についても見ていきましょう。 なので紹介しておきますが、ローレベルの数字文字列変換についてです。数字のデータがあって、これを文字列に変換します。型変換をするときには変換イニシャライザーを使うのが基本的な流儀です。
変換イニシャライザーとは、変換先の型に搭載されているイニシャライザーで、渡された値をそのまま型変換するものです。ラベルなしのイニシャライザーとして提供されるため、最初のパラメータにラベルがありません。ラベル付きのものは解釈を伴うことが多いです。
例えば、
Int
を取って
Double
を返す変換イニシャライザーを使えば、以下のように数値を文字列に変換できます。
let number = 42 let string = String(number)
このように、素直な数値からの文字列変換の場合には変換イニシャライザーを使うと良いです。数値から文字列変換と言えば、おそらく多くの開発者は
String
初期化子を思い浮かべるかもしれませんが、フォーマッタを使った変換もあります。
例えば、
0
詰めしたい場合には
String(format:)
を使います。
let number = 42 let formattedString = String(format: "%03d", number)
この
String(format:)
はFoundationに含まれているので、普通の環境で使う場合には問題ないでしょう。ただし、一部の環境では利用できませんので注意が必要です。
また、16進数表現に変換したい場合も
String(format:)
を使うことができます。
let number = 42 let hexString = String(format: "%x", number)
このように、簡単な文字列変換であれば、この方法が便利です。
String
には、標準ライブラリでも16進数や8進数に変換する方法が用意されています。16進数に変換する場合は以下のようにします。
let number = 42 let hexString = String(number, radix: 16)
大文字にしたい場合は、変換後に
uppercased()
メソッドを使います。
let upperHexString = hexString.uppercased()
8進数に変換したい場合は、以下のようにします。
let octalString = String(number, radix: 8)
整数型に対しても変換イニシャライザーを使うことで、独自の変換が可能です。この場合、数値が文字列から変換されるのを容易に行えます。
基本的に、純粋な型変換を行う場合はその型の変換イニシャライザーを使います。これにより、より良いコードが書けると思います。
他に通常の文字列に変換する方法があれば、それも活用できますが、基本的にはこれらの方法を覚えておけば十分です。
さて、今回はこのあたりで終わりにしましょう。次回はUIテーブルビューの話題に入る予定です。では、お疲れ様でした。ありがとうございました。