困った時の自分用メモ

読んだ本を考察してメモったり、自分でいじった物の感想をメモったりする場。週1更新を目指します。

MACスタンドアローンアプリの話〜MACスタンドアローンアプリのハマりどころ〜

MAC上で動くデスクトップアプリを作ろうと思った。
実は、初めての試みだった。
そして、案の定色々ハマったので、その備忘録をしておく。

今回は、Windowsデスクトップアプリと同じだと思っているとハマる点の備忘録

○アプリケーションの閉じるボタン=アプリの終了ではない
これは、実際に試してみればわかるのだが、デフォのままアプリを実行した場合、閉じるボタンを押してもアプリが画面下部バーに残り続ける。

これを解決するには、AppDelegate.mに下記処理を追加する。

- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
    return YES;
}

これを書けば、閉じるボタンを押せば画面下部バーからも消えてくれる。

○DS_STOREファイルは、MAC上では可視化できないが、プログラム上でファイル検索すると、リストアップに含まれる
MAC上では、DS_STOREファイルは可視化できず操作もできないらしいので、 DS_STOREファイルを無視するような処理を入れる必要がある。

○外部ファイルアクセスができない?
APP内に含めている(=バンドル化されている)リソースへのアクセスは容易だが、外部データへのアクセスは難しいようだった。
例えば、

// バンドルに含まれている物の読み込み
NSString *path = [[NSBundle mainBundle] pathForResource:@"SoundName" ofType:@"mp3"];
NSURL* url = [NSURL fileURLWithPath:path];
[[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];

これなら読み込めるのだが、

NSString *path = @"/Users/UserName/Desktop/Res/Sound.mp3";

NSFileManager *filemanager = [ NSFileManager defaultManager];
BOOL isDir = NO;
//ディレクトリの確認
if([filemanager fileExistsAtPath:path isDirectory:&isDir]){
    if( isDir == YES ){
        printf("ディレクトリです。n");
    }else{
        // ファイルの存在確認はできる
        printf("ファイルです。n");
    }
}

NSURL* url = [NSURL fileURLWithPath:path];
[[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];

とすると、権限が無い的なエラーが出て読み込みに失敗する。

新しいOSでは、アクセス権限的な物をフォルダに付与する事も可能らしいが、 それを、配布するユーザー毎に毎回お願いするのもおかしいので、外部ファイルへのアクセスという考え方は、やめたほうが良さそうだ。

○じゃぁ、リソースの変更はどうやる?
実は、APPアプリを右クリックして「パッケージの内容を表示」をすると、バンドルに含めたリソースがそのまんま入っている。 そして、うまくいく読み込みのパスは、このリソースまでのパスである。 つまり、この中身を入れ替えてしまえば、対応可能だったりする(実証済み)

○作ったアプリを他人の環境で実行するときは、右クリ→開くをする必要がある
許可が下りていないところからダウンロードされたアプリは、実行に権限を付与する必要があるらしい。
で、それは右クリ→開くで可能になるようだ。

○データをセーブする時
こんな感じで、簡単に実装できるようだ。
ただ、どこに保存されるのかまでは、よく調べていない。

// 保存
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
[ud setInteger:100 forKey:@"Volume1"];
[ud synchronize];

// 読み込み
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
long volume1 = [ud integerForKey:@"Volume1"];

○アプリ終了時のイベントフック
データをセーブするタイミングは、アプリ終了時とかで自動で保存したいデータもあると思う。 そういう場合は、AppDelegate.mにこんな感じで書いておくといい。

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    // 終了時に保存するための処理
    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    [nc addObserver:self selector:@selector(OnEndCallback) name:NSApplicationWillTerminateNotification object:nil];
}

-(void)OnEndCallback{
    printf("end");
}