忍者ブログ

[PR]

2024年03月19日
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

iOS6における画面回転への対応方法

2013年04月07日
iOS5や6になって画面の表示前に出されるメッセージ(一般的な言い方をすると関数でしょうか)群にかなり変更があり、昔のプロジェクトのままだとなんだか画面のレイアウトがおかしいぞということになりやすいです。とりあえず自分の経験でこうすれば良いのではないかという対処法について書いてゆきます。

まず、画面を表示させたときにレイアウトに問題がある場合には、その問題のあるパーツを管理するViewControllerのメソッドファイル内で、viewWillAppear:の中で初期化するようにしておくと良いです。現在ない状態なら作っておきましょう。画面の回転状態でレイアウトを変更する必要がある場合には、現在の画面の回転状態を[[UIApplication sharedApplication]statusBarOrientation]で取得します。横向きのそれぞれで別のレイアウトにすることは稀ですから、画面が横向きかどうかをUIInterfaceOrientationIsLandscape()マクロをif文の中に放り込んで、カッコの中に先ほどの[[UIApplication sharedApplication]statusBarOrientation]を入れて画面が横向きかの判定をすれば良いでしょう。回転状態などの判定部分についてまとめると以下のような感じです。

    UIInterfaceOrientation interfaceOrientation=[[UIApplication sharedApplication]statusBarOrientation];
    if (UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPad) {
        if (UIInterfaceOrientationIsLandscape(interfaceOrientation)) {
            // iPadで画面が横向きのときの初期レイアウトを以下に追加
        } else {
            // iPadで画面が縦向きのときの初期レイアウトを以下に追加
        }
    } else if(UIInterfaceOrientationIsLandscape(interfaceOrientation)){
        // iPhone/iPod touchで画面が横向きのときの初期レイアウトを以下に追加
    } else {
        // iPhone/iPod touchで画面が横向きのときの初期レイアウトを以下に追加
    }

そしてshouldAutorotateToInterfaceOrientation:にはとりあえず向きに応じてYESで回転許可、NOで回転不可を返す部分だけは(iOS6以上では呼び出されることすら無いのですが)一応書いておいて、実際に回転でレイアウトをいじる部分に関してはwillAnimateRotationToInterfaceOrientation:duration:の中でtoInterfaceOrientationを使って仕分けを行って、実際のレイアウト変更を行うという形になります。

これだけやればiOS6以上でレイアウトが崩れる問題は解決出来るでしょう。当然ながらstoryboradやnibファイルで作っているUIパーツについては事前にヘッダ側でIBOutletを含むプロパティを作成して接続済みにしておきましょう。
PR

Xcodeの変更点

2012年04月29日
ご無沙汰してるあいだにXcodeも随分と変化していました。最近のXcodeで変更になっている主な部分は、

  • ストーリーボードの導入
  • ARC(Automatic Reference Counting)の導入

といったところでしょうか。
以前にInterface BuilderがXcodeと一体になった事はブログで取り上げたと思いますが、ストーリーボードはさらに一体化を推し進め、画面(シーン)間の関係もUI設計の側で扱えるようになっています。また、ARCの導入をすると自分でretainとreleaseを書かなくても良くなり(実際のところ書いては駄目になる)、多くのクラスでreleaseが廃止されています。しばらくはドキュメントを見ながらの格闘になりそうです。

iOS5へのアップデート

2011年07月12日
久しぶりに更新します。ここ数ヶ月別の方面で忙しく、開発関係に割ける時間がありませんでした。ここにきて少しだけ時間が作れるようになりました。

そこでまず実機にiOS5のβ版でも入れてみようとしたところ、何度やってもエラーが出て止まってしまいます。実機がリカバリモードになってしまいiTunesからiOS4.3.3を入れ直して復旧しました。そして再チャレンジしてみますが、またリカバリモードになって復旧しての繰り返しとなってしまいます。いろいろ調べてみたところ、どうも今回のβ版からは、

XCodeのオーガナイザからのアップデートはできない

ということのようです。ではどうすればよいのかというと、iTunesのβ版からアップデートします。

まずiTunesのβ版と自分のデバイス用のiOS5βをiOS Dev Centerからダウンロードして、iTunesのβ版をインストールします。デバイスのデータのバックアップを取っておきたい場合はインストールの前に取っておいてください。
アップデートが終わったらiTunesを起動しのウインドウ左のDEVICESからアップデートしたいデバイスを選択し、中央付近に表示されるVersionのところにあるRestoreボタンをoption(alt)ボタンを押しながらクリックしてみてください。iOS5βのダウンロードが終わっていればリストに展開されたディスクイメージが表示されているはずなので、そこからipswファイルを選んでOKを押します。

これまでオーガナイザを使ってβ版を入れていた人で私と同じようにはまっている人がいたら試してみてください。たぶんそれまでのハマりっぷりが嘘のようにすんなりとアップデート出来ますよ。

アイコンのユニバーサル化

2010年04月27日
iPhone/iPod touchはアイコンサイズが57×57ですが、iPadは72×72です。そのためアイコンファイルは2個用意する必要があります。ところが現在のiPhone SDK 3.2のテンプレートでは、たとえ新規作成でWindow-based Applicationを選びProductをUniversalにしても、アイコンの設定項目は1個だけです。このままビルドしてもユニバーサルアプリケーションの要件を満たせないため、自分でアイコンのユニバーサル化を行う必要があります。

1.まずはプロジェクト内にある〜Info.plistを開きます。
2.新しくキーを追加します。キーの名前はCFBundleIconFilesです。
3.追加したキーの上でCtrlを押しつつマウスボタンをクリック(2ボタンマウスなら単に右クリック)し、メニューからValue typeのArrayを選びます。
4.中を展開し2個のアイテムを追加します。それぞれの値に用意した57×57と、72×72のアイコン名をセットします。

これでアイコンのユニバーサル化は完了です。これまでの設定であるIcon fileキーは放置でも念のためiPhone/iPod touch用を書いておいても、キー自体を消してしまっても問題は無いようです。

当日追記:
Easy RDS バージョン1.1(ユニバーサル対応版)が承認されましたので、アイコンについてはこの方法で問題ないことが確定しました。ちなみにIcon fileキーには念のためiPhone/iPod touch用のアイコンファイル名を書いてビルドしています。

1つのコードでiPhone/iPod touch/iPadに対応する

2010年04月26日
1つのコードで全てのiPhone OSデバイスをサポートできればソースコードの管理が楽になります。今回の記事はそんな方法を紹介します。今後のことは分かりませんが、現状ではこの分岐方法を使えば全てのデバイスに対応するコードが書けます。まず例としてコードの一部を示します。

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {

// iPad

UIGraphicsBeginImageContext(CGSizeMake(900.0,675.0));

} else {

// iPhone or iPod touch(iPhone OS バージョン3.2以上)

UIGraphicsBeginImageContext(CGSizeMake(360.0,240.0));

}

#else

// iPhone or iPod touch(iPhone OS バージョン3.2未満)

UIGraphicsBeginImageContext(CGSizeMake(360.0,240.0));

#endif


始めの行のマクロでOSのバージョン判定を行います。iPhone OSのバージョンが3.2以上だと、次にユーザーンターフェースタイプの判定を行います。この2つの判定を組み合わせる事で実行されるデバイスによりアプリケーションの動作を変える事が出来ます。

この他にも[[UIDevice currentDevice] systemVersion]で返ってくる文字列を使って判定する方法もありますが、その方法はお勧めできません。その方法ではiPhone SimulatorでiPhone側の動作確認を行なおうとアクティブSDKを3.1.3などに切り替えた場合、iPad用のコードの中にiPhone SDK 3.2で追加されたメソッドがあると、そんな命令無いぞとビルドエラーが起きてしまうからです。

iPhone SDK 3.x で iPhone OS 2.x 向けアプリケーションを開発する

2009年10月11日
 アプリケーションの動作対象OSを2.1(第2世代iPod touch発売開始時のプレインストールOSでした)など旧バージョンにも拡大したい場合、以下の方法で可能になります。まず前提として、iPhone SDK 3.xのインストール時に出るチェックボックスで旧バージョンのOS用SDKにもチェックを入れておきます。もしこれをしていない場合には、もう一度インストールし直しチェックを入れておきます。インストールは上書きで問題ありません。

  1. Xcodeでプロジェクトを開き、左のリストで一番上のプロジェクトファイルをクリック、さらに情報アイコンをクリックして、ビルドタブを開きます。
  2. コード署名(Code signing)セクションの下にある、Deploymentセクション最上段のiPhone OS Deployment Targetの値をクリックします。
  3. インストールされているSDKに対応したOSが表示されるので、目的のOSを選択します。

これでXcode左上のリストにSDKの選択肢が出せるようになります。

ここで注意すべきなのは、たとえ2.xをターゲットにしていようと、新規ファイルは3.x前提のテンプレートから作成される点です。「iPhone OS 3.0 におけるセルの変更点」で書いた通り、セルの初期化メソッドはinitWithFrame:reuseIdentifier:からinitWithStyle:reuseIdentifier:へ変更になっているため、新規ファイルでUITableViewCellのサブクラスを作った場合、初期化メソッドに手直しをしなければなりません。また、UITableViewControllerのサブクラスでも、tableView:cellForRowAtIndexPath:メソッドの内容を修正する必要があります。

また、OpenGL ES applicationのテンプレートからプロジェクトを作成した場合には、テンプレートがOpen GL ES 2.0のシェーダーに対応するものに変わっているので、この場合もかなり大掛かりな修正が必要になります。SDK 2.xの頃から使っている人でないと、どこを変更すれば良いか分かりにくいと思いますので、iPhone SDK 3.x から始めた人は素直に(?)3.x向けで開発したほうが良いかもしれません。

iPhone SDK 3.1 の新規作成

2009年10月11日
 Xcodeのバージョンアップに伴い新規ファイルの区分がまた少し変更になっているので、自分がよく使いそうな範囲のみですがまとめておきます。

NSObject、UITableViewCell、UIViewのサブクラスのヘッダファイルとメソッドファイル作る場合
iPhone OS > Cocoa Touch Class > Objective-C classを選択

UIViewController、UITableViewControllerのサブクラスのヘッダファイルとメソッドファイル作る場合
iPhone OS > Cocoa Touch Class > UIViewController subclassを選択
ヘッダファイル等と同じ名前のXIBファイルを作るオプションも追加されている

自分でビューのXIBファイルだけ作る場合
iPhone OS > User Interface > View XIBを選択

ローカライズ用のstringsファイルを作成する場合
Other(左のリスト下から2番目にある) > Strings File
追加したファイルの情報を見て、一般のローカリゼーションを追加...から言語選択を行うのも忘れずに

iPhoneアプリケーション開発でautoreleaseが非推奨の理由

2009年09月22日
アップル社公式の開発ガイドなどでは、iPhone OSをターゲットとしたアプリケーションを開発する場合、autoreleaseはなるべく避けるようにと書いてあります。この記事ではその理由を掘り下げてみようと思います。

この理由を明かす前に、まず推奨となっているretain countでの管理と、autoreleaseでの管理の違いを説明します。retain countで管理されているオブジェクトは、それをメモリー上に残しておきたい場合にretain countを0より大きい値になるようにしておきます。そのオブジェクトがallocやretainされるとカウントが増加し、releaseされればカウントが減少します。カウントが0になった状態でrun loop(ユーザーからの入力などのイベント処理)に入ると、そのオブジェクトはメモリー上から消滅します。この方法だと、オブジェクトは必要な時にメモリーを確保して、不要になると早いうちに解放されます。解放されたメモリーは別のオブジェクトの保持等にまわす事ができるので、無駄が少なくなります。

では非推奨のautoreleaseではどうなっているかというと、NSAutoreleasePoolという仕掛けがあり、この中にオブジェクトが追加されるようになっています。このNSAutoreleasePoolもオブジェクトで、これは前述のretain countで管理されています。この中に入っているオブジェクトは、それを入れている器であるNSAutoreleasePoolが解放されたときに、同時に解放されるようになっています。Xcodeでテンプレートからアプリケーションのプロジェクトを作った場合、このNSAutoreleasePoolは1つだけ自動で作られるようになっていますが、問題はこのNSAutoreleasePoolが解放されるタイミングが、「アプリケーションを終了したとき」になることです。従って、後述する対策を行わずにいると、アプリケーションで作られたautorelease付きのオブジェクトや、クラスメソッドと呼ばれる+印で始まるメソッドから返ってきたオブジェクトは全てこのNSAutoreleasePoolに入れられてしまい、アプリケーションを終了するまで解放されずに残ってしまうのです。これらによってメモリーが消費されてしまうと、アプリケーションが使えるメモリー領域はどんどん狭くなってしまいます。Mac OS Xで動いているマシンであればメモリーの量もそれなりにあるのであまり問題になりませんが、iPhone OSではそこまでメモリーを贅沢に使えるわけでもないので、アプリケーションを終了するまで誰も使えなくなるゴミ領域はなるべく作らない方が良いことになります。それこそがautorelease非推奨の理由なのです。

とはいえ、クラスメソッドには他で代替できないものや、代替可能でも長いコードを書かなければならない場合等もあります。そのためにautoreleaseオブジェクトの解放タイミングを早める対策方法も用意されています。実はNSAutoreleasePoolは何個も作る事ができ、メソッドの始めにNSAutoreleasePoolオブジェクトを作成すると、そのメソッド内で作られたautoreleaseオブジェクトは全てそのNSAutoreleasePoolオブジェクトの管理下に置かれます。そのため、メソッドから抜ける前にそれを解放すると、管理下にあるautoreleaseオブジェクトも同時に解放されるようになるのです。つまり、

- (void)myMethod {

NSAutoreleasePool *myAutoreleasePool = [[NSAutoreleasePool alloc] init];

NSString *string = [NSString stringWithString:@"myAutoreleasePool管理オブジェクト"];

NSLog(string);

[myAutoreleasePool release];

}
 

というようにメソッドを書けば、その中で作ったオブジェクトはアプリケーションの終了を待たずに解放されます。おそらく解放のタイミングは、

- (void)myMethod {

NSString *string = [[NSString alloc] initWithString:@"retain count管理オブジェクト"];

NSLog(string);

[string release];

}


このように書いている場合と大差ないものと思われます。大量に一時オブジェクトを作るようなメソッドでこのような対策を行っておけば、メモリーのゴミ領域を削減することができるわけです。

2009年10月2日追記
一般的なアプリケーションではイベントループの開始時点で自動的にプールが作成される仕組みもあるため、上に書いてあるように、自分でプールを追加しないとアプリケーション終了までオブジェクトが消滅しないということはありませんでした。ただし意図的に別スレッドを作った場合などはオブジェクトが残ることがあるので、このような場合は明示的にプールを作成、解放をしたほうが良いでしょう。
 | HOME | 次のページ »