2014年10月26日日曜日

日付時刻も間接参照で(続編:時間進行倍率を変更)

前回は、日付時刻の間接参照を利用し、時間をシフトすることで、テストが楽になることを紹介しました。実は、さらなる技があるのです。続編として紹介しましょう。

 

時間シフト以外の、簡単で実用的な例として面白いのが、時間の進み具合を変更する機能です。進み具合というのは、時間の経過速度のことです。

アプリで使っているマシンの時計は、1秒間に1秒だけ進みます。当たり前ですよね。これが狂っていたら大変なことになります。でも、それを「自由に」変えられたらどうでしょうか。1秒間に2秒だけ進むとか、逆に1秒間に0.5秒だけ進むとか。前者は速く進み、後者は遅く進んでいることとなります。

 

何に使うのか疑問に思う人もいるでしょう。でも、役立つ場合もあるのです。たとえば、1時間ごとに自動で、何かを処理するアプリがあったとします。1時間待てますか。もちろん、時間シフト機能を使って、1時間ごとに時刻をずらし、テストしても構わないでしょう。

でも、時間が通常より速く進められたら、どうでしょう。仮に3600倍速にしたら、1秒ごとに1時間だけ進みます。処理時間が必要なので、ちょっと速すぎますね。もう少し遅くして、10秒ごとに1時間だけ進んだらどうでしょう。240秒(=4分)で1日分の処理が確認できてしまいます。本来なら1時間ごとに始まる処理が、10秒ごとに始まって、たった4分で1日分が確認できるわけです。凄いと思いませんか?

 

さっそく、作りましょう。現在の日付時刻を取得するメソッドに、少し細工するだけです。必要な変数は2つです。開始時刻を記録した変数「dateStart」と、進行倍率を保持する変数「timeRetio」です。

動作は簡単です。準備として「dateStart」に開始時刻を記録し、「timeRetio」に倍率を設定しておきます。今の日付時刻が必要になったら、「getDateNowF」メソッドを呼び出します。その中では、現在の時刻と「dateStart」との時差を求め、それに倍率「timeRetio」を乗算します。乗算した値を「dateStart」に加えた時刻を返すというわけです。swiftで書くと、次のようになります。

// 時間進行の倍率を変える機能が付いた、現在の日付時刻を取得するメソッド
var dateStart : NSDate = NSDate()
var timeRetio : Double = 1.0
func getDateNowF() -> NSDate {
    let realTimeInterval : NSTimeInterval = dateStart.timeIntervalSinceNow
    let vartualTimeInterval : NSTimeInterval = realTimeInterval * timeRetio * -1.0
    let vartualDate = dateStart.dateByAddingTimeInterval(vartualTimeInterval)
return vartualDate
}

こんなに短いソースで、実現できてしまいました。

 

もちろん、これだけでは不十分ですね。進行倍率を設定するメソッドも必要です。

// 進行の倍率係数を設定するメソッド
func setTimeRatio(rRatio:Double) {
    timeRetio = rRatio
}

さらには、進行のスタートをリセットするメソッドもあると、いろいろ便利でしょう。

// 倍率進行の開始時刻をリセットするメソッド
func resetStartDate() {
    dateStart = NSDate() // 基準となる時刻を、現在の時刻に再設定
}

どちらのメソッドも、非常に簡単です。

ここで、あれれと気付いた人もいるでしょう。「NSDate()」が使われているため、「NSDate()」が一カ所ではなくなっているのです。この機能の実現には、「getDateNowF」メソッドを使うわけにもいかず、「NSDate()」しか選択肢がありません。日付取得にいろいろな機能を加えていくと、日付取得の「NSDate()」を一カ所だけに限定することができず、やむを得ず複数箇所になってしまいます。これは仕方ないでしょうね。コメントなどで、複数箇所あることを明示しておきましょう。

(余談:選択肢がないと書きましたが、「getDateNowF」メソッドの処理内容を逆補正すれば、「getDateNowF」メソッドを使って「NSDate()」と同等の処理を実現できます。でも、「getDateNowF」メソッドの変更と同時に、逆補正の処理も変更する必要が生じ、修正しずらい機能になってしまいます。だから実質的には選択肢になり得ません)

 

一応、使い方も紹介しておきますね。前回とほぼ同じですが、インスタンス生成直後に、時間の進行倍率を設定するコードが加わります。

// クラスを使う
let zDate = DateController() // 適切なタイミングでインスタンス生成
zDate.setTimeRatio(360.0)    // 10秒で1時間進む設定に変更
 ...
labelDate.text = zDate.getDateStrNowF() // 必要な箇所で使う
 ...
zDate.resetStartDate() // 必要に応じてリセット

使う側の内容は、前回と似た感じになってしまいました。一応はいろいろと考えましたが、良い例が思い浮かびませんでした(汗)。

 

swiftのソースを見て分かるように、時間の進行倍率は、現在の時刻を求めるときに使うだけで、ずっと計測しているわけではありません。このような仕組みなので、2種類以上の進行倍率を並行して使うことも可能です。

この場合も、使い方は簡単です。時刻を取得する直前に、必要な進行倍率に設定するだけです。進行倍率の設定と時刻取得を、すべてペアで使うということです。swiftで書くと、次のようになります。

// 2種類の進行倍率を使う
let zDate = DateController() // 適切なタイミングでインスタンス生成
 ...
zDate.setTimeRatio(360.0)
date360 = zDate.getDateNowF() // ケース1の必要な箇所で使う
 ...
zDate.setTimeRatio(180.0)
date180 = zDate.getDateNowF() // ケース2の必要な箇所で使う
 ...
zDate.setTimeRatio(360.0)
date360 = zDate.getDateNowF() // ケース1の必要な箇所で使う
 ...

見てのとおり、簡単ですね。

 

ここで紹介した時間の進行倍率を使ったテストでは、他の要素を考慮していません。アプリの処理内容によっては、時間以外の部分で何か用意する必要があるでしょう。「時間が速く進むことによる副作用」も考慮しながら、上手に使うことが求められます。

 

日付時刻を間接参照で作ると、いろいろと面白い機能が実現できます。その例として、少し変わった使い方を紹介しました。とにかく大事なのは、日付のような外部からの入力は、1カ所にまとめるということです。

0 件のコメント:

コメントを投稿