Objective-Cで現在時刻をミリ秒で取得する5つのステップ

Objective-Cコード例と時計Objctive-C
この記事は約23分で読めます。

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

Objective-Cは、主にAppleのiOSおよびmacOSでアプリケーションを開発するためのプログラミング言語です。

Objective-Cのコードを書くときに、時折、現在時刻をミリ秒単位で取得したい状況があります。

例えば、アプリのパフォーマンス測定や、ユーザーイベントの正確なタイミングをログに記録する必要がある場合です。

本文書では、Objective-Cを使用して現在の時刻をミリ秒で取得する手順を5つのステップに分けて詳しく解説します。

●Objective-Cとは

Objective-CはC言語にSmalltalkスタイルのメッセージ送信機能を加えたオブジェクト指向言語です。

1980年代にBrad CoxとTom Loveによって開発され、Appleによってその後大幅に拡張されてきました。

この言語は、NeXTのオペレーティングシステムからiOSとmacOSに至るまで、長い間Appleの開発環境で重要な役割を果たしてきました。

○Objective-Cの歴史

Objective-Cは、C言語の構文にSmalltalkのオブジェクト指向の概念を組み合わせたものとして登場しました。

その直感的なオブジェクト管理と、動的なランタイム機能は、複雑なソフトウェア開発をより管理しやすくするために設計されています。

Objective-Cは、AppleのMacintoshで初めて使われて以来、iOSの登場とともにモバイル開発の主流言語の一つとなり、広く使用されるようになりました。

○Objective-Cの特徴

Objective-Cの特徴の一つには、強力なランタイム機能があります。

これにより、プログラムは実行時にクラスやメソッドの情報を取得したり、変更したりすることができます。

また、C言語のすべての機能に加えて、クラス継承、ポリモーフィズム、インターフェースなどのオブジェクト指向プログラミングの概念をサポートしています。

ガベージコレクションのサポートが終了した後は、ARC(Automatic Reference Counting)がメモリ管理の負担を軽減します。

次に、Objective-Cで現在時刻のミリ秒単位での取得の重要性について述べる前に、時間測定の精度がアプリケーションにとってどれほど重要かを理解することが不可欠です。

高精度の時間データは、イベントのタイミングを正確に記録したり、アニメーションや音声の同期、ゲーム内の物理演算など、多岐にわたるアプリケーションの機能に影響を与えます。

特に、マルチメディア処理や科学技術計算においては、ミリ秒単位での時間取得が欠かせません。

●現在時刻のミリ秒単位での取得の重要性

現在時刻のミリ秒単位での取得は、アプリケーションのパフォーマンス測定、ユーザーの操作に対する応答時間の改善、マルチメディアアプリケーションの同期、あるいは科学技術計算において重要です。

コンピュータシステム内でのプロセスやイベントを正確にタイムスタンプすることは、データの整合性確保やデバッグ作業を行う際にも不可欠な役割を果たします。

特に、リアルタイムシステムやゲーム開発では、ミリ秒単位での時間追跡が絶対に欠かせません。

さらに、ネットワーク通信におけるタイムアウトの管理やセキュリティ関連のタイムスタンプにも精度が求められます。

これらの場合、不正確な時刻情報は、システム全体の信頼性を低下させる可能性があるため、Objective-Cを含むあらゆるプログラミング言語で正確な時刻取得が強調されます。

○ミリ秒単位の時間が必要な場合

ミリ秒単位の時間は、取引のタイムスタンプとしての金融市場や、ユーザーの入力とアプリケーションの出力との間の遅延を最小限に抑えるためのインタラクティブシステムなど、さまざまなアプリケーションで必要とされます。

例えば、音楽制作ソフトウェアでは、音の録音と再生を正確に同期させるためにミリ秒単位での時間取得が必要です。

また、スポーツのタイミング測定では、わずかな時間差が競技結果に大きく影響を及ぼすため、高精度な時刻計測が求められます。

このような状況では、単なる秒数ではなく、より細かいミリ秒単位での時刻情報が不可欠であるため、Objective-Cにおいても適切な取得方法を知ることが重要となります。

●Objective-Cでの現在時刻ミリ秒取得方法

プログラミングにおいて、現在時刻のミリ秒単位での取得は、パフォーマンス測定やタイミングの精密な制御を必要とする多くのアプリケーションにとって不可欠です。

Objective-Cを使用してiOSアプリケーションを開発している際、システム時刻をミリ秒で取得する方法は複数存在します。

この記事では、Objective-Cで現在時刻をミリ秒で取得するための具体的なステップとそのサンプルコードを、2つの異なる方法で詳しく解説します。

○サンプルコード1:NSDateを使用する

Objective-Cでは、NSDateクラスを使って現在時刻を取得し、これをミリ秒に変換することができます。

下記のサンプルコードは、NSDateオブジェクトを使用して現在時刻のタイムスタンプをミリ秒で取得する方法を表しています。

// 現在時刻を取得するNSDateオブジェクトの作成
NSDate *now = [NSDate date];
// 時刻をミリ秒単位で取得するために、1970年1月1日からの時間を秒で取得し、1000を掛ける
NSTimeInterval timeIntervalSince1970InMilliSec = [now timeIntervalSince1970] * 1000.0;
// ミリ秒単位の時間を整数に変換
long long currentTimeInMilliSec = llround(timeIntervalSince1970InMilliSec);
// 現在のミリ秒単位の時刻を表示する
NSLog(@"現在時刻のミリ秒: %lld", currentTimeInMilliSec);

このコードではNSDateクラスを利用して現在時刻を取得し、timeIntervalSince1970メソッドで1970年1月1日からの経過時間を秒単位で取得しています。

その後、1000を掛けることでミリ秒単位に変換し、llround関数を使って最も近い整数値に丸めています。

最後にNSLog関数を使用し、ミリ秒単位で取得した現在時刻をコンソールに出力しています。

このコードを実行すると、コンソールに現在のミリ秒単位での時刻が表示されるため、実際にどれだけの時間が経過しているかを精密に把握することができます。

○サンプルコード2:システムアップタイムを利用する

別の方法として、iOSデバイスのシステムアップタイムを利用して、アプリケーションが起動してからの経過時間をミリ秒単位で取得することができます。

システムアップタイムはデバイスが最後に再起動されてからの時間であり、スリープ状態を含まないため、実際にデバイスが動作している時間のみを計測することができます。

// システムアップタイムを取得するための構造体を定義する
#include <sys/sysctl.h>

// システムアップタイムをミリ秒で取得する関数
void getSystemUptimeInMilliseconds() {
    struct timeval boottime;
    int mib[2] = {CTL_KERN, KERN_BOOTTIME};
    size_t size = sizeof(boottime);
    struct timeval now;
    struct timezone tz;
    gettimeofday(&now, &tz);

    // システムの起動時間を取得する
    if ((sysctl(mib, 2, &boottime, &size, NULL, 0) != -1) && (boottime.tv_sec != 0)) {
        // 現在時刻と起動時刻の差を計算する
        double uptime = now.tv_sec - boottime.tv_sec;
        uptime += (now.tv_usec - boottime.tv_usec) / 1000000.0;
        // ミリ秒に変換する
        long long uptimeInMilliseconds = llround(uptime * 1000.0);
        NSLog(@"システムアップタイム: %lld ミリ秒", uptimeInMilliseconds);
    }
}

getSystemUptimeInMilliseconds();

このコードでは、sysctl関数を使用してシステムの起動時間をtimeval構造体に取得し、gettimeofday関数で現在時刻を取得しています。

その後、起動時刻と現在時刻の差を秒単位で算出し、さらにマイクロ秒の差を加算して正確な経過時間を計算しています。

最後に経過時間をミリ秒に変換し、コンソールに出力することで、システムが起動してからの精確なアップタイムをミリ秒単位で表示しています。

これらのコードは、Objective-Cを使用したiOSアプリケーション開発における時間計測のための実践的な例として役立ちます。

時間に関連する機能を開発する際にこれらのコードを参照にすることで、ユーザーにとってより快適で正確な体験を提供することが可能になります。

●Objective-Cでの現在時刻ミリ秒取得方法

Objective-Cで現在時刻をミリ秒単位で取得する技術は、精度の高いタイミングやパフォーマンス測定に不可欠です。

iOS開発では特に、ユーザーインターフェースのレスポンス時間の計測や、ゲームのフレームレートの最適化など、多くのシーンで正確な時間測定が求められます。

この記事では、Objective-Cを用いて時刻をミリ秒単位で取得する様々な方法を紹介し、それぞれの実装方法と使用シナリオについて詳しく説明します。

○サンプルコード3:timeval構造体を使う

このコードではgettimeofday関数とtimeval構造体を使って、現在の時刻をマイクロ秒単位まで取得し、それをミリ秒に変換しています。

この方法はUnix系OSで広くサポートされているため、iOSやmacOS開発においても有効です。

#include <sys/time.h>

void getCurrentTimeInMilliseconds() {
    struct timeval time;
    gettimeofday(&time, NULL); // 現在の時刻を取得
    long milliseconds = (time.tv_sec * 1000) + (time.tv_usec / 1000); // 秒をミリ秒に変換し、マイクロ秒を加算
    printf("Current time: %ld milliseconds\n", milliseconds);
}

この関数を呼び出すと、timeval構造体のtv_secフィールドには現在時刻の秒が、tv_usecフィールドにはマイクロ秒が格納されます。

これらを適切に変換・計算することでミリ秒単位の現在時刻を取得できます。

○サンプルコード4:mach_absolute_timeを使う

mach_absolute_time関数は、デバイスが最後に起動してからの経過時間をナノ秒単位で提供します。

しかし、この値を直接使用するにはいくつか変換ステップが必要です。

下記のコードは、mach_absolute_timeを使用して経過時間をミリ秒単位で取得する方法を表しています。

#include <mach/mach_time.h>

void getElapsedTimeInMilliseconds() {
    static mach_timebase_info_data_t timebase_info;
    if (timebase_info.denom == 0) {
        (void)mach_timebase_info(&timebase_info); // 時間単位の変換情報を取得
    }
    uint64_t timeNano = mach_absolute_time() * timebase_info.numer / timebase_info.denom; // ナノ秒単位に変換
    uint64_t timeMilli = timeNano / 1000000; // ナノ秒をミリ秒に変換
    printf("Elapsed time: %llu milliseconds\n", timeMilli);
}

初回呼び出し時にはmach_timebase_info関数で時間単位の変換情報を取得し、mach_absolute_time関数の返す値をナノ秒単位に変換後、それを更にミリ秒に変換しています。

この関数を使用することで、システムの起動からの経過時間を高精度で取得することが可能です。

○サンプルコード5:カスタムメソッドを作成する

Objective-Cで現在時刻をミリ秒単位で取得するためのカスタムメソッドを作成することもできます。

ここでは、NSDateクラスを拡張してミリ秒で現在時刻を返すメソッドの実装例を紹介します。

#import <Foundation/Foundation.h>

@interface NSDate (MillisecondPrecision)
+ (long)currentMilliseconds;
@end

@implementation NSDate (MillisecondPrecision)
+ (long)currentMilliseconds {
    return (long)([[NSDate date] timeIntervalSince1970] * 1000.0);
}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        long currentMillis = [NSDate currentMilliseconds];
        NSLog(@"Current time: %ld milliseconds", currentMillis);
    }
    return 0;
}

この拡張メソッドでは、NSDateオブジェクトのtimeIntervalSince1970メソッドを使い、エポック時間(1970年1月1日からの経過秒数)をミリ秒に変換しています。

これにより、非常に簡単に現在時刻のミリ秒を取得することができます。

実際にこのコードを実行すると、現在時刻のミリ秒単位の値をコンソールに出力します。

プログラムが表す出力は、プログラムが実行された瞬間の時刻に依存するため、毎回異なる値になります。

これを使って、タイミングを測るアプリケーションや、イベントが発生した正確なタイムスタンプをログに記録するなど、様々な用途で役立てることができます。

●応用例

Objective-Cを学んだ後、得られた知識をどのように実践に活かすかは、学習者にとって非常に重要です。

ここでは、Objective-Cを使用して具体的な応用例を3つ紹介します。

これらの例は、現在時刻をミリ秒単位で取得する方法を理解した上で、さらに応用する形での実装例となります。

○サンプルコード1:ストップウォッチ機能の実装

ストップウォッチは、スポーツイベントや学習時間の管理など、日常生活の中で広く使われています。

Objective-Cでストップウォッチ機能を実装する際には、下記のようなコードを使用することができます。

#import <Foundation/Foundation.h>

@interface Stopwatch : NSObject
@property (nonatomic, strong) NSDate *start;
- (void)start;
- (NSTimeInterval)elapsedTime;
@end

@implementation Stopwatch

- (void)start {
    self.start = [NSDate date];
}

- (NSTimeInterval)elapsedTime {
    return [[NSDate date] timeIntervalSinceDate:self.start] * 1000;
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Stopwatch *stopwatch = [[Stopwatch alloc] init];
        [stopwatch start];
        // 何らかの処理
        NSLog(@"経過時間: %f ミリ秒", [stopwatch elapsedTime]);
    }
    return 0;
}

このコードでは、Stopwatch クラスを定義し、現在時刻のミリ秒単位での取得を可能にしています。

start メソッドを呼び出すことで計測を開始し、elapsedTime メソッドで経過時間をミリ秒単位で取得しています。

このコードを実行すると、NSLog で出力された経過時間を確認することができます。

○サンプルコード2:時間計測ツールの作成

開発時に関数やメソッドの実行時間を計測したい場合があります。

Objective-Cで簡単な時間計測ツールを作成する例を紹介します。

#import <Foundation/Foundation.h>

@interface TimeMeasurer : NSObject
@property (nonatomic, strong) NSDate *start;
- (void)startMeasure;
- (void)stopAndReport;
@end

@implementation TimeMeasurer

- (void)startMeasure {
    self.start = [NSDate date];
}

- (void)stopAndReport {
    NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:self.start] * 1000;
    NSLog(@"実行時間: %f ミリ秒", duration);
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        TimeMeasurer *measurer = [[TimeMeasurer alloc] init];
        [measurer startMeasure];
        // ここで実行時間を計測したい処理を行う
        [measurer stopAndReport];
    }
    return 0;
}

このコードではTimeMeasurer クラスを使って実行時間を計測しています。

処理を開始する前にstartMeasureメソッドを、処理が終了した後にstopAndReportメソッドを呼び出すことで、実行時間をミリ秒単位で計測し、コンソールに出力します。

○サンプルコード3:パフォーマンス測定

パフォーマンス測定には、Objective-Cでの高精度の時間測定が不可欠です。

ここではtimeval構造体を使用して、現在の時刻をミリ秒まで取得するサンプルコードを見ていきましょう。

#include <sys/time.h>

// 現在時刻をミリ秒で取得する関数
double getCurrentTimeMillis() {
    struct timeval time;
    gettimeofday(&time, NULL); // 現在の時刻を取得
    long seconds = time.tv_sec; // 秒単位の時刻
    long micros = time.tv_usec; // マイクロ秒単位の時刻
    // 秒とマイクロ秒をミリ秒に変換
    return (seconds * 1000) + (micros / 1000);
}

int main() {
    double millis = getCurrentTimeMillis();
    printf("Current time: %f milliseconds\n", millis);
    return 0;
}

このコードでは、sys/time.hヘッダー内のgettimeofday関数を使って、timeval構造体に現在時刻を秒とマイクロ秒で格納しています。

その後、これらを合算しミリ秒に変換することで、高精度の現在時刻を取得しています。

printf関数を使用して、結果を標準出力に表示しています。

この例では、UNIXエポックからの経過時間をミリ秒単位で取得し、プログラムの実行時点での時間をミリ秒で表示しています。

このコードを実行すると、コンソールに現在の時刻がミリ秒単位で表示されます。

表示される値はプログラムを実行するたびに変わり、実行された瞬間の時間を反映しています。

これにより、アプリケーションの特定の処理にかかる時間を計測する際に基準点として使用することが可能になります。

●注意点と対処法

Objective-Cで現在時刻をミリ秒単位で取得する際には、数点の注意が必要です。

第一に、取得した時刻の精度は使用するAPIやデバイスの状況に大きく依存します。

APIの仕様変更により、以前は使用できたメソッドが非推奨となることもあるため、最新の情報に留意する必要があります。

また、複数の時刻取得メソッドを組み合わせることで精度を高めることができますが、その際の処理負荷も考慮する必要があります。

Objective-Cでは、精度の高い時刻を得るためには、正確なタイミングでコードを実行することが求められます。

しかし、高精度な時刻取得の試みは、アプリケーションのパフォーマンスに影響を与えかねません。

したがって、時刻取得のコードは、必要最小限の処理にとどめ、アプリケーション全体のパフォーマンスを損なわないように注意深く設計する必要があります。

非推奨となったAPIを使用すると、将来のOSアップデートでアプリケーションが正常に動作しなくなる可能性があります。

これを防ぐためには、Appleのドキュメントを頻繁に確認し、推奨されるメソッドに適宜更新することが必要です。

アプリの互換性を保ちつつ、より良いユーザー体験を提供するためには、新しいAPIの採用と古いAPIからの移行計画が重要です。

○時刻取得の精度

Objective-Cにおける時刻取得の精度を向上させるためには、NSDateのような高レベルのAPIだけでなく、システムのアップタイムやmach_absolute_timeなどの低レベルAPIを適切に使用することが勧められます。

NSDateはシステムの時計を基に現在時刻を返しますが、システムアップタイムはデバイスが最後に起動してからの経過時間を、mach_absolute_timeはCPUのサイクル数を基に時間を計測します。

これらの方法は異なる種類の時刻データを提供し、それぞれにユニークな利点と制限があります。

たとえば、NSDateは次のようなコードで現在時刻のミリ秒を取得することができます。

NSDate *now = [NSDate date];
NSTimeInterval nowEpochSeconds = [now timeIntervalSince1970];
NSInteger nowMilliseconds = (NSInteger)(nowEpochSeconds * 1000.0);

このコードではNSDateクラスを使ってエポック時間(1970年1月1日からの秒数)を取得し、それをミリ秒に変換しています。

この例ではNSTimeInterval型のnowEpochSecondsが現在時刻の秒を保持し、NSInteger型のnowMillisecondsにその値をミリ秒に変換して保持させています。

○パフォーマンスの最適化

時刻取得のパフォーマンスを最適化するためには、時刻取得の処理をアプリケーションのメインスレッドから分離し、非同期処理を行うことが一つの方法です。

非同期処理を利用することで、UIの応答性を維持しつつ、処理が完了するまでの待機時間をユーザーに感じさせないようにすることが可能です。

また、時間の精度が必要ない場合は、より少ない精度での時刻取得を検討し、不必要なリソースの消費を避けることが重要です。

時刻取得の呼び出し回数を削減することや、タイマーの解像度を調整することも、パフォーマンスの改善に役立ちます。

○非推奨APIの取り扱い

非推奨APIの使用に関しては、開発者は新しいAPIへの更新計画を常に用意しておくべきです。

時とともに非推奨とされるメソッドは、セキュリティリスクや互換性の問題を引き起こすため、アプリケーションの安定性と信頼性を維持するためには、これらのAPIからの移行を早急に計画し実行することが推奨されます。

●カスタマイズ方法

Objective-Cでの開発において、現在時刻のミリ秒取得機能は多くのアプリケーションで必要とされています。

しかし、デフォルトの設定だけでは、ユーザーのニーズに合わせた最適な時刻表示を提供することが難しい場合があります。

このため、カスタマイズは重要な役割を果たします。

カスタマイズのプロセスには、ユーザーインターフェースの改善、機能の拡張、そしてローカライズへの対応が含まれます。

これらのプロセスを通じて、アプリケーションはより使いやすく、また多くの市場に対応することが可能となります。

カスタマイズ方法を踏まえ、次に具体的なサンプルコードを交えて、Objective-Cにおける時刻表示のカスタマイズ方法と、ロケールに合わせた時間形式の調整方法について解説します。

○時刻表示のカスタマイズ

Objective-Cで現在時刻を表示する際、デフォルトでは24時間制や12時間制といった基本的な形式が用いられますが、アプリケーションによってはこれらの形式をカスタマイズして、特定のフォーマットで表示する必要があります。

例えば、時刻だけでなく、曜日や日付も表示したい場合や、時間に応じて異なる言語で出力する必要がある場合です。

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy年MM月dd日 EEE HH時mm分ss秒 SSS"]; // 年月日と曜日、時分秒ミリ秒を含むフォーマット
NSDate *now = [NSDate date];
NSString *formattedDateString = [formatter stringFromDate:now];
NSLog(@"%@", formattedDateString);

このコードでは、NSDateFormatterクラスを使っています。

まずNSDateFormatterのインスタンスを生成し、setDateFormatメソッドによって年月日(yyyy年MM月dd日)、曜日(EEE)、時間(HH時mm分ss秒)、ミリ秒(SSS)を含むカスタムフォーマットを設定しています。

NSDateクラスのdateメソッドを使用して現在時刻の情報を取得し、formatterによって指定されたフォーマットに基づいて文字列に変換されます。最後にNSLogを使用してカスタマイズされた時刻情報をコンソールに出力します。

上記コードを実行すると、次のような出力結果を得ることができます。

2023年11月06日 月 15時45分12秒 345

○ロケールに合わせた時間形式

グローバルに展開するアプリケーションでは、異なる地域のユーザーに合わせた時間表示が求められます。

Objective-Cでは、NSLocaleクラスを使用してロケール情報を取得し、それに応じた日付フォーマットを設定することができます。

NSLocale *locale = [NSLocale localeWithLocaleIdentifier:@"ja_JP"]; // 日本のロケールを設定
[formatter setLocale:locale];
[formatter setDateStyle:NSDateFormatterFullStyle]; // フルスタイルで日付を設定
[formatter setTimeStyle:NSDateFormatterMediumStyle]; // ミディアムスタイルで時間を設定
NSString *localizedDateString = [formatter stringFromDate:now];
NSLog(@"%@", localizedDateString);

ここでは、NSLocaleクラスのlocaleWithLocaleIdentifierメソッドを使って特定のロケールを指定しています。

NSDateFormatterにはsetLocaleメソッドを使用してこのロケールを設定し、setDateStyleおよびsetTimeStyleメソッドで日付と時間の表示スタイルを定めています。

すると、formatterはロケールに基づいた日付と時間のフォーマットで現在時刻を文字列に変換します。

最後にNSLogで変換結果をコンソールに表示させます。

上記のコード実行により、次のような出力が得られます。

2023年11月6日月曜日 15時45分12秒

まとめ

Objective-Cを用いた現在時刻のミリ秒取得は、高精度な時間測定を必要とするアプリケーション開発において重要な技術です。

本記事では、その取得方法を5つのステップで詳細に説明しました。

NSDateの利用から、より精密な時間を求めるmach_absolute_timeの使用まで、各ステップには初心者にも分かりやすいサンプルコードを紹介しました。

本記事で解説したポイントを踏まえながら開発を進めることで、ユーザーにとってより良い体験を提供するアプリケーションを作成することが可能になります。