お疲れ様です。堺です。
当社で開発している「おしぼりAI」のアプリ開発(iOSネイティブ)で、サービスの実行を日付に依存させたいタスクがあり、端末外部から日時情報を取得するためにKronosというライブラリを導入しました。
非公式情報を頼りに実装してみたのですが、実際動かしてみると思わぬハマり方をして手戻りが出るという事態がありました。
今回はそのような失敗を踏まえ、「Clock.nowがnilを返す/Clock.sync()が機能しない」という問題および実装上の注意点について共有しようと思います。
この記事の目標:これからSwiftで時刻取得を実装する人の出戻りを減らしたい
結論:時刻取得はこう実装する+注意点
基本的にはClock.sync()のクロージャに、取得後の処理を実装するのが良いです。
GitHubのUsageの通りです。
↓OKな実装方法
Swift
Clock.sync { now, offset in
print(now)
}
↓NGな実装方法
Swift
Clock.sync()
let now = Clock.sync() //syncの非同期処理が完了する前に呼ばれるので、Clock.sync()がnilを返す
上記コメントの通り、注意したいのは、Clock.syncのクロージャが呼ばれるまで大体5~10秒くらいの時間を要するという点です。(手元実測)
ユーザーを待たせるには少々辛い時間なので、正確な時刻が得られるまで数秒のディレイがある前提でUXを工夫する必要があるということですね。
この点理解しておかないと、UXを根本から検討し直しになり、私のように手戻りを起こしてしまいます。
もしKronosで時刻を取得する処理を深い位置にあるビューで使用するのであれば、そこに辿り着く前にあらかじめsyncを呼んでおくのが良いかと思います。
代替手段を検討してみたが・・・
とはいえ、クロージャが呼ばれるまで待つのは不便です。
代替として、AppDelegateでsyncを呼んでLaunchScreenを長時間表示する方向性も考えましたが、それはそれで極めてイマイチでした。
仕方がないので、syncが完了する前にトップビューが表示されるのはやむなしということとなりました。
Swift/AppDelegate.swift
import UIKit
import Kronos
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
Clock.sync()
sleep(10) //LaunchScreenが10秒表示されてしまう
return true
}
//以下省略
Kronosに関して前提知識が未調達な方へ、簡単な解説
Kronosは、端末外部から現在時刻を取得することができる、Swiftでの開発で利用可能なライブラリの一つです。
現在時刻を取得するだけなら
Swift
let now = Date()
というコードで標準ライブラリのみで取得できるのですが、この取得値は端末設定に依存します。
例えば今日は2021年11月8日ですが、端末の時刻設定を2020年11月8日に変更すると、2020年の値が取得でき、このようにユーザー側で任意に取得値を改変することができます。
そこで、ユーザーの設定によらず現在の日時を取得するために、今回のようなライブラリを導入して実装を行なっています。
参考リンク
KronosのGitHubです。Usageなどが掲載されています。
GitHub - MobileNativeFoundation/Kronos
記事筆者へのお問い合わせ、仕事のご依頼
当社では、IT活用をはじめ、業務効率化やM&A、管理会計など幅広い分野でコンサルティング事業・IT開発事業を行っております。
この記事をご覧になり、もし相談してみたい点などがあれば、ぜひ問い合わせフォームまでご連絡ください。
皆様のご投稿をお待ちしております。