クロックに時報を追加する

2010. 05. 31
さて、今度はクロックへの時報を追加を行います。

●サンプルアプリケーションの概要

335

クロックの作成』で作ったクロックアプリケーションを改造して時報を設定するのですが、見た目は何も変わりません。

追加する作業としましては、

1)時報用タイマーの設置

2)時報用サウンドファイルの追加

3)サウンド再生のファイルとフレームワークの追加

4)サウンド再生用のデリゲートの対応

5)サウンド再生メソッドの追加

となります。


●時報用タイマーの設置


・時報用タイマーの宣言

XcodeでClockAppDelegate.hを開き、時報用タイマーの宣言を追加します。
(太字が追加した部分)

#import <UIKit/UIKit.h>

@interface WebAppDelegate : NSObject <UIApplicationDelegate> {
    IBOutlet UILabel *labelDate;    // 日付表示
    IBOutlet UILabel *labelTime;    // 時刻表示
    NSTimer *timerClock;    // 時計更新用タイマー
    NSTimer *timerAnnounce;    // 時報用タイマー
    UIWindow *window;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@end

349

時計更新用タイマーのtimerClockは単一メソッドなので、アプリケーション起動直後に発動するapplication:didFinishLaunchingWithOptions:内に直接記述していますが、時報用タイマーのtimerAnnounceは日時の取得などの処理があるため別メソッドとして起こしています。


・アプリ起動直後のapplication:didFinishLaunchingWithOptions:でのタイマー呼び出し

ClockAppDelegate.mのapplication:didFinishLaunchingWithOptions:で、時報用タイマーのメソッドsetupTimeAnnounceを呼び出します。
(太字が追加した部分)

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // Override point for customization after application launch

    timerClock = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateClock:) userInfo:nil repeats:YES];

    [self setupTimeAnnounce];

    [window makeKeyAndVisible];

    return YES;
}

351


・時報用タイマーの実装

呼び出すメソッドを記述ですが、この際呼び出しているapplication:didFinishLaunchingWithOptions:より前にsetupTimeAnnounceを記述してください。
(『呼び出すメソッドが無い』とコンパイルエラーが出ますので)

- (void)setupTimeAnnounce {
    // 時報用のタイマーを生成
    timerAnnounce = [NSTimer scheduledTimerWithTimeInterval:60.0f target:self selector:@selector(playAnnounce:) userInfo:nil repeats:YES];

    // 現在の日時とカレントのカレンダーを取得
    NSDate *date = [NSDate date];
    NSCalendar *cal = [NSCalendar currentCalendar];
    NSDateComponents *cmp = [cal components:NSSecondCalendarUnit fromDate:date];

    // 次の時報の日時を取得
    NSDate *dateAnnounce = [NSDate dateWithTimeIntervalSinceNow:60.0f - [cmp second]];

    // 時報の日時を設定
    [timerAnnounce setFireDate:dateAnnounce];
}

350

時報用タイマーの設定は時計更新用タイマーと同じく、scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:メソッドを使います。

異なる点は、

・60.0秒間隔で発火
・発火時にplayAnnounce:(時報用再生メソッド)を呼び出し

の2点です。

次にタイマーの発火時刻を設定します。

手順は、

1)dateメソッドで現在時刻の取得
2)currentCalendarメソッドで現在のロケールのカレンダーを取得
3)取得した時刻とカレンダーを使用し、components:fromDate:メソッドで日付コンポーネントを生成
4)発火時間を補正(今回の場合、各分の0秒で発火)するため、dateWithTimeIntervalSinceNow:メソッドで差分の時間を追加
5)補正した発火時間をsetFireDate:メソッドで設定

となっています。

date、currentCalendar、components:fromDate:、dateWithTimeIntervalSinceNow:メソッドについては『Foundation(日付と時間)』を参照してください。


・setFireDate:
(NSTimerクラス)

- (void)setFireDate:(NSDate *)date

レシーバで設定されている発火時間を再設定します

このメソッドは通常、リピートタイマーの発火時間の調整に使用します

タイマーの次の発火時間を再設定は比較的高くつく操作ですが、いくつかの状況では効率的です

例えば、不規則な時間間隔で、複数の時刻に動作を繰り返す状況では有効です

1つの実行ループのスケジューリングの中で複数のタイマーオブジェクトを作成・破棄をするより、1つのタイマーの発火時間を調整した方がよりコストを少なくできます

無効になっているタイマーや、発火済みの非リピートタイマーでこのメソッドを呼び出さないでください

ただし、スレッドに常に接続されている潜在的な競合状況を避けるためのタイマーの場合、未発火の非リピートタイマーからこのメソッドを潜在的に呼び出すことができます

date:新しく再設定する発火の日時を指定します
新しい日付が既に過ぎていた場合、このメソッドは現在の時刻を発火時間に設定します


●サウンド再生のファイルとフレームワークの追加

時報用のサウンドファイルは、自作できればそれに越したことはないのですが、ファイルフォーマットやデータフォーマット、コーデックなどがまだ理解できていないので、『基礎からのiPhone SDK 改訂版』のサンプルコードを出版社のサイトからダウンロードして、iPhoneBG2.zipを展開、『SampleCode』 → 『50.04.Clock ( 時報 )』フォルダ下のtime1.cafファイルをコピーして使います。

同ファイルを自分のプロジェクトフォルダにコピーし、そこからプロジェクトのResourcesフォルダにドラッグ&ドロップします。

今回はサウンドの再生に唯一のObjective-Cインターフェイスである、AVAudioPlayerをしようするのでFrameworksを右クリックして『追加』→『既存のフレームワーク』でAVFoundation.frameworkを追加します。

352

『サウンド再生用のデリゲートの対応』の前に、AVAudioPlayerDelegateプロトコルの説明をします。


●AVAudioPlayerDelegateプロトコル

AVAudioPlayerオブジェクトのデリゲートは、AVAudioPlayerDelegateプロトコルを採用しなければなりません。

このプロトコルの全てのメソッドはオプションです。

デリゲートは、サウンド再生の完了やオーディオのデコード、オーディオの中断などに対応します。


・AudioPlayerBeginInterruption:
(AVAudioPlayerDelegateプロトコル)

- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player

電話の呼び出しなどでオーディオプレイヤが中断された時に呼び出されます

中断されると、アプリケーションのオーディオセッションは非アクティブとなり、オーディオプレイヤが一時停止します

中断終了の通知を受け取るまで、オーディオプレイヤを再開することはできません

player:中断されたオーディオプレイヤを指定します


・audioPlayerDecodeErrorDidOccur:error:
(AVAudioPlayerDelegateプロトコル)

- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error

オーディオプレイヤの再生中にデコードエラーが発生した時に呼び出されます

player:デコードエラーが発生したオーディオプレイヤを指定します

error:デコードエラー


・audioPlayerDidFinishPlaying:successfully:
(AVAudioPlayerDelegateプロトコル)

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag

サウンドの再生が完了した時に呼び出されます

このメソッドは、オーディオが中断された時には呼び出されません

中断されるとオーディオプレイヤは一時停止し、サウンドの再生は完了しません

player:再生を完了したオーディオプレイヤを指定します

flag:再生が完了した場合はYESを、システムがオーディオデータのデコードをできなかった場合はNOを返します


・audioPlayerEndInterruption:
(AVAudioPlayerDelegateプロトコル)

- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player

ユーザが電話の呼び出しを無視するなどで、中断が終了すると呼び出されます

中断が終了すると、アプリケーションは自動的にオーディオセッションを再アクティブ化し、オーディオプレイヤと対話できます

再生を再開するには、playメソッドを呼び出します

player:中断の終了したオーディオプレイヤを指定します


●サウンド再生用のデリゲートの対応

Core Audioの復習』のAVAudioPlayerでも述べていますが、AVAudioPlayerを利用するにはデリゲートに対応(AVAudioPlayerDelegateの採用)しなければなりません。

プロトコルについての詳細は『Objective-C言語のメモ書き(4)』を参照してください。

AVAudioPlayerDelegateプロトコルの場合、全てのメソッドがオプションなので必要なければ実装する必要が無く、ClockAppDelegate.hにAVAudioPlayerDelegateプロトコルを追加するだけで済みます。
(太字が追加した部分)

@interface ClockAppDelegate : NSObject <UIApplicationDelegate, AVAudioPlayerDelegate> {
IBOutlet UILabel *labelDate; // 日付表示
IBOutlet UILabel *labelTime; // 時刻表示
NSTimer *timerClock; // 時計更新用タイマー
NSTimer *timerAnnounce; // 時報用タイマー
UIWindow *window;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@end

353

今回の場合は、AVAudioPlayerのインスタンス破棄のため、audioPlayerBeginInterruption:メソッドを実装しています。

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)avap successfully:(BOOL)flag {
    // インスタンスを破棄
    [avap release];
}

354

audioPlayerDidFinishPlaying:successfully:メソッドはオーディオプレイヤが再生を完了した時に呼び出されます。


●サウンド再生メソッドの追加

最後に時報を鳴らすplayAnnounce:メソッドを実装します。

時報用のサウンドファイル(time1.caf)を読み込んで再生するので、アプリケーションバンドルを取得し、バンドルからサウンドファイルのパスを取得、URLに変換します。

URLに変換するのは、AVAudioPlayerのサウンドファイル指定がNSURL形式なためです。

そして、通知を受け取るデリゲートの設定をし、サウンドを再生します。

- (void)playAnnounce:(NSTimer *)timer {
    // アプリケーションのバンドルを取得
    NSBundle *bundle = [NSBundle mainBundle];

    // リソースのファイルパスを取得
    NSString *path = [bundle pathForResource:@"time1" ofType:@"caf"];

    // ファイルパスからURLを生成
    NSURL *url = [NSURL fileURLWithPath:path];

    // AVAudioPlayerのインスタンス生成
    AVAudioPlayer *avap = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];

    // デリゲートの設定
    avap.delegate = self;

    // サウンドの再生
    [avap play];
}

355

mainBundleメソッドで現在実行しているアプリケーションのディレクトリ位置を確認し、pathForResource:ofType:メソッドでファイル名と拡張子からファイルを特定します。

mainBundleとpathForResource:ofType:メソッドの詳細については『Foundation(バンドル)』を参照してください。


・fileURLWithPath:
(NSURLクラス)

+ (id)fileURLWithPath:(NSString *)path

指定したパスからファイルURLのNSURLオブジェクトを新規に作成し、初期化して返します

このメソッドは、pathがスラッシュ(/)で終わるディレクトリであることを仮定しています

pathがスラッシュで終わっていない場合、pathがファイルシステムにあるファイルまたはディレクトリかどうかをメソッドが調べます

pathがファイルシステムのディレクトリに存在する場合、メソッドは末尾にスラッシュを付加します

pathがファイルシステムに存在しない場合、ファイルを表しているものと仮定して、メソッドは末尾にスラッシュを付加しません

代替案として、fileURLWithPath:isDirectory:を使って、返されるNSURLオブジェクトがファイルまたはディレクトリを表すかどうかを明示的にすることも検討してください

path:NSURLオブジェクトで表すパスを指定します
指定するパスは、有効なシステムパスにする必要があります
パスがチルダ(~)で始まる場合は、最初にstringByExpandingTildeInPathで展開する必要があります
このパラメータにnilを渡すと例外が発生します


・initWithContentsOfURL:error:
(AVAudioPlayerクラス)

- (id)initWithContentsOfURL:(NSURL *)url error:(NSError **)outError

指定したサウンドファイルを再生するオーディオプレイヤを初期化して返します

成功した場合はAVAudioPlayerオブジェクトを初期化します

戻り値がnilの場合は、outErrorパラメータに含まれている問題を説明するコードを参照してください

url:再生するサウンドファイルのURLを指定します
オーディオデータは、Core Audioがサポートしているフォーマットである必要があります

outError:成功した場合はnilを、失敗した場合はエラーコードが含まれます


・delegate
(AVAudioPlayerクラス)

@property(assign) id<AVAudioPlayerDelegate> delegate

オーディオプレイヤのデリゲートオブジェクトを返します

このオブジェクトは、オーディオプレイヤのデリゲートとして、AVAudioPlayerDelegateプロトコルの通知のターゲットに割り当てられます

これらの通知には、デコードエラーや電話の呼び出しによるオーディオの中断、再生の完了などがあります


・play
(AVAudioPlayerクラス)

- (BOOL)play

非同期のサウンドを再生します

戻り値は、成功した場合はYESを、失敗した場合はNOを返します

もしオーディオプレイヤが事前に再生の準備ができていない場合、このメソッドは暗黙的にprepareToPlayメソッドを呼び出します



参考文献

AVAudioPlayerDelegate Protocol Reference

AVAudioPlayer Class Reference

NSURL Class Reference

基礎からのiOS SDK基礎からのiOS SDK
(2010/10/09)
鶴薗 賢吾、松浦 健一郎 他

商品詳細を見る






SoundLink Mini Bluetooth speaker_ii_limited
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
05 | 2017/06 | 07
Sun Mon Tue Wed Thu Fri Sat
- - - - 1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 -
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

Author:水月杏香
永遠の初心者プログラマ。

Wish List
WACOM


ARC
Technical Q&A
情報プロパティリストキー
Start Developing iOS Apps Today
BOSE

SoundLink Mini Bluetooth speaker_ii_limited
Reference
NSApplicationDelegateプロトコル
NSArrayクラス
NSAutoreleasePoolクラス
NSBundleクラス
NSBundle UIKit追加分
NSCalendarクラス
NSCoderクラス
NSCodingプロトコル
NSCopyingプロトコル
NSDataクラス
NSDateクラス
NSDateFormatterクラス
NSDictionaryクラス
NSEntityDescriptionクラス
NSEnumeratorクラス
NSErrorクラス
NSExceptionクラス
NSFetchRequestクラス
NSFileHandleクラス
NSFileManagerクラス
NSIndexPathクラス
NSIndexPath UIKit追加分
NSKeyedArchiverクラス
NSKeyedUnarchiverクラス
NSKeyValueCodingプロトコル
NSLocaleクラス
NSManagedObjectクラス
NSManagedObjectContextクラス
NSManagedObjectModelクラス
NSMutableArrayクラス
NSMutableCopyingプロトコル
NSMutableDictionaryクラス
NSMutableSetクラス
NSNotificationクラス
NSNotificationCenterクラス
NSNullクラス
NSNumberクラス
NSObjectクラス
NSObject UIKit追加分
NSObjectプロトコル
NSPersistentStoreクラス
NSPersistentStoreCoordinatorクラス
NSPredicateクラス
NSPropertyListSerializationクラス
NSRunLoopクラス
NSSetクラス
NSStringクラス
NSString UIKit追加分
NSTimerクラス
NSTimeZoneクラス
NSURLクラス
NSURLProtectionSpaceクラス
NSURLRequestクラス
NSUserDefaultsクラス
NSValueクラス

UIActionSheetクラス
UIActionSheetDelegateプロトコル
UIActivityIndicatorViewクラス
UIAlertViewクラス
UIAlertViewDelegateプロトコル
UIApplicationクラス
UIApplicationDelegateプロトコル
UIBarButtonItemクラス
UIBarItemクラス
UIButtonクラス
UIColorクラス
UIControlクラス
UIDatePickerクラス
UIDeviceクラス
UIEventクラス
UIFontクラス
UIGestureRecognizerクラス
UIImageクラス
UIImageViewクラス
UIKit Function
UILabelクラス
UINavigationControllerクラス
UINavigationItemクラス
UIPickerViewクラス
UIPickerViewDataSourceプロトコル
UIPickerViewDelegateプロトコル
UIPinchGestureRecognizerクラス
UIResponderクラス
UIScreenクラス
UIScrollViewクラス
UISearchBarクラス
UISearchBarDelegateプロトコル
UISegmentedControlクラス
UISliderクラス
UISwipeGestureRecognizerクラス
UISwitchクラス
UITableViewクラス
UITableViewCellクラス
UITableViewControllerクラス
UITableViewDataSourceプロトコル
UITableViewDelegateプロトコル
UITapGestureRecognizerクラス
UITextFieldクラス
UITextFieldDelegateプロトコル
UITextInputTraitsプロトコル
UITextViewクラス
UITextViewDelegateプロトコル
UIToolbarクラス
UITouchクラス
UIViewクラス
UIViewControllerクラス
UIWebViewクラス
UIWebViewDelegateプロトコル
UIWindowクラス

AVAudioPlayerクラス
AVAudioPlayerDelegateプロトコル

CADisplayLinkクラス
CAEAGLLayerクラス
CALayerクラス

CGAffineTransform
CGBitmapContext
CGColor
CGColorSpace
CGContext
CGGeometry
CGImage
CGPath

EAGLContextクラス
EAGLDrawableプロトコル

Foundation Constants
Foundation Data Types
Foundation Functions

MPMediaItemクラス
MPMediaItemArtworkクラス
MPMediaPlaylistクラス
MPMediaPropertyPredicateクラス
MPMediaQueryクラス
MPMusicPlayerControllerクラス

Randomization Services

System Sound Services
Amazon


OpenGL ES
SQLite
Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
Visitors
QR Code
QR