iPhone SDK 4 を入れてみた – アプリ開発はどう変わるか(1)

私は、手持ちの3GSをiOS4にしているのですが、iPhone SDK 4 をインストールして遊んでみました。
今の今いれてちょこっと遊んだだけなのですが、ちょっと雑感を書いてみる。

● iPhoneシミュレータに「iPhone4」が追加されている

まず、iPhoneシミュレータの「ハードウェア」-「デバイス」-「iPhone4」として、大きさを体験してみる。

結構な大きさ。これだけの大きさのものがあの小さなディスプレイで見えるのですから、どれだけiPhone4のディスプレイが綺麗かが分かりますね。

 

● アプリケーションのマルチタスク化はどうすれば実現できるのか?
iOS4のマルチタスク化で、開発する側は何をすればいいのか。今までと開発手法は変わるんだろうか。

そこで、簡単なアプリケーションを作ってみました。画面をタップするとカウントアップするカウンターと、カウントダウンタイマーをつけて1秒に1デクリメントするようにする。こんな画面

startを押すと残り時間が1秒に1ずつ減り、タップすると、0のところが1,2,3,4と増えるってだけのアプリ。プログラムは特に今まで通りの組み方です。今までならホームボタンを押せば、終了して、もう一回起動すると最初からとなりますが、iPhone4ではどうなるか。

start押して、画面をタップする。カウンタがインクリメントされて、残り時間は減っています。

ここで、ホームボタンを押す。iPhone3GS以前では、これでアプリは終わりますが、iPhone4はバックグラウンドで停止したような状態になります。

ホームボタンをダブルクリックすると、バックグラウンドで動いているアプリの一覧が表示されますので、
該当のアプリをタップして起動してみると・・・

おー、ちゃんと再開されている。残り時間は止めてあるあいだ減ってはいません。冷凍保存して、急速解凍して、心臓が再び動き出した感じです。
もう一回ホームボタンを押す→ホームボタンをダブルクリック→該当のアプリを長押し→マイナス(ー)をタップして完全終了です。

というわけで、今まで通り作ってビルドすれば、マルチタスク対応になるっぽいです。

 

● マルチタスキングに伴う、UIApplicationDelegateのメソッド追加
xcodeで最初に生成されるUIApplicationDelegateのコードもちょっと変わっている気がする。
なんか見慣れないけど、それっぽいメソッドがある。

- (void)applicationWillResignActive:(UIApplication *)application
- (void)applicationDidEnterBackground:(UIApplication *)application
- (void)applicationWillEnterForeground:(UIApplication *)application
- (void)applicationDidBecomeActive:(UIApplication *)application
- (void)applicationWillTerminate:(UIApplication *)application

実際にどのタイミングで呼ばれるかを調べてみました。

【起動時】
- (void)applicationDidBecomeActive:(UIApplication *)application

【ホームボタンを押して中断】
- (void)applicationWillResignActive:(UIApplication *)application
- (void)applicationDidEnterBackground:(UIApplication *)application
の順番で呼ばれる

【復帰】
- (void)applicationWillEnterForeground:(UIApplication *)application
- (void)applicationDidBecomeActive:(UIApplication *)application
の順番で呼ばれる

という感じです。

あれ、applicationWillTerminateは呼ばれないの?と思い公式ドキュメントを見てみると

For applications that support background execution, this method is generally not called when the user quits the application because the application simply moves to the background in that case. However, this method may be called in situations where the application is running in the background (not suspended) and the system needs to terminate it for some reason.

私のヘボ訳です。

バックグラウンドでの実行をサポートしているアプリケーションにおいては、ユーザがアプリケーションを終了しても、このメソッドは一般的には呼ばれることはありません。なぜならば、単にバックグラウンド移っただけだからです。しかしながら、このメソッドはアプリケーションがバックグラウンドでサスペンドせずに動いているときに呼ばれることがあるかもしれません。

ってことらしいので、普通のアプリでは呼ばれないらしい。iPhone4では「一部のアプリを覗いて」バックグラウンドではサスペンド状態、いわゆる凍結状態になっているので、呼ばれないよということです。バックグラウンドでも位置情報を取得するようなアプリケーションでは呼ばれることがあるのかもしれない。

 

● マルチタスクをサポートしているかどうか調べる
ユーザの端末がマルチタスクをサポートしているかどうかは、以下のコードで調べられる(公式ドキュメントより引用)

UIDevice* device = [UIDevice currentDevice];
BOOL backgroundSupported = NO;
if ([device respondsToSelector:@selector(isMultitaskingSupported)])
backgroundSupported = device.multitaskingSupported;

 

● まとめ
まあ、そんなわけで、今まで通りプログラムを組んで、最新のSDKでビルドすれば、ホームボタンを押して中断した状態が維持され、再び起動したときに、中断した状態から再開するっていう結論でございます。中断再開時に必要に応じた処理をすることもできます。
あと、上記テストプログラムにおいて、デバッグの時に、iPhoneシミュレータで完全にプロセスを切って再起動すると、真っ黒な画面しか出てこないんですが、実機に転送してやったら、ちゃんと動いて、大きな問題はありませんでした。

さっき1時間ほどさくっと触って書いてますので、間違ったことも書いてあるかもしれませんが、その時は優しくコメント欄でご指摘くださいまし。
また、しばらくいじくって分かったことをメモしていきたいと思います。

Posted on 6月 25, 2010 at 4:18 PM by まるやま · Permalink · コメント
In: メモ · Tagged with: , , , ,

シンプルなアラートを表示するには(メッセージとボタン1個)

シンプルなアラートを表示する方法。JavaScriptでいうalert()です。

- (IBAction) buttonClicked {
UIAlertView *alert = [[UIAlertView alloc] init];
alert.title = @"警告";
alert.message = @"ボタンが押されました";
[alert addButtonWithTitle:@"はい"];
[alert show];
[alert release];
}

そうするとこうなります。

上記では UIAlertViewをアロケートして、initした後にtitleとmessageプロパティを呼び出し、addButtonWithTitleメソッドでボタンのラベルを指定し、ボタンを追加しています。

以下のように書きなおすことができます。

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"警告"
message:@"ボタンが押されました"
delegate:nil
cancelButtonTitle:nil
otherButtonTitles:@"はい", nil];
[alert show];
[alert release];

アラート上のボタンが押されたのをトリガーになにか処理をさせたり、その他のボタンやキャンセルボタンをここにつけることもできますが、そのへんは後日別途書くことにしよう。

Posted on 6月 15, 2010 at 2:17 PM by まるやま · Permalink · コメント
In: 逆引きリファレンス, 通知

URLを指定して、そのページのHTMLを取得するには

特定のページのHTMLを取得するには、以下のようにしています。

NSURL *url = [NSURL URLWithString:@"http://www.omnibase.net/"];
NSString *html = [NSString stringWithContentsOfURL:url encoding:NSShiftJISStringEncoding error:nil];

NSURLのURLWithStringメソッドの引数に取得したいURLを指定します。そうするとNSURL型のオブジェクトが取得できるので、それをNSStringのstringWithContentsOfURL: encoding: error: に渡すと、NSStringでHTML文字列が帰ってきます。

encoding: のところには、取得先ページの文字コードを指定します。NSStringEncoding型の定数を指定します。

NSASCIIStringEncoding … ASCIIコード
NSJapaneseEUCStringEncoding … EUC-JP
NSUTF8StringEncoding … UTF8
NSShiftJISStringEncoding … Shift-JIS
NSISO2022JPStringEncoding … ISO-2022-JP(JIS)

error: は NSError型のオブジェクトへのポインタを渡すのですが、エラーに興味なければ nil を指定すればいいのです。そもそもエラーなら返り値がnilになりますので、私はnilをして、if(html == nil) みたいな感じで処理します。もしNSError型でエラーを捕捉する場合、

NSError *error;
NSURL *url = [NSURL URLWithString:@"http://www.omnibase.net/"];
NSString *html = [NSString stringWithContentsOfURL:url encoding:NSShiftJISStringEncoding error:&error];

とすればいいのです。

さて、encodeで取得先の文字コードを指定するの面倒なんで、自動取得できないかなーと思ってますが、私はうまい解決策を知りません。一応、NSStringにstringWithContentsOfURL: useEncoding: error: というメソッドはあるにはあります。useEncodingにはNSStringEncoding型のポインタを渡すと、そこに読み込まれた文字列の文字コードを格納してくれるはずなんですが・・・実際にやってみるとうまくいかない。

NSStringEncoding enc;
NSURL *url = [NSURL URLWithString:@"http://www.omnibase.net"];
NSString *html = [NSString stringWithContentsOfURL:url usedEncoding:&enc error:nil];

http://www.omnibase.net/ の文字列がUTF8以外の場合、encには0が、htmlはnilとなってうまく取得できない。UTF8にしたところうまく取得できました。

まとめ

+ (id)stringWithContentsOfURL:(NSURL *)url encoding:(NSStringEncoding)enc error:(NSError **)error

urlで指定されたページの文字列を取得する。取得できない場合、指定された文字コードが異なる場合はnilが返るらしい。

url
取得先URL
enc
 文字コード
error
 エラーの詳細を知りたい場合はNSError型のオブジェクト 。不要の場合nil。

+ (id)stringWithContentsOfURL:(NSURL *)url usedEncoding:(NSStringEncoding *)enc error:(NSError **)error

urlで指定されたページの文字列を取得する。取得した文字コードをencで指定されたアドレスに格納する。日本語ではUTF8以外は取得できないらしい。

url
取得先URL
enc
 文字コードを格納するポインタ。
error
 エラーの詳細を知りたい場合はNSError型のオブジェクト 。不要の場合nil。

Posted on 6月 13, 2010 at 9:32 PM by まるやま · Permalink · コメント
In: 文字列, 逆引きリファレンス · Tagged with: , , , , , , , ,