西海岸より

つらつらざつざつと

アプリのiOS5のアップデート対応

iOS5が公開され、既存アプリのiOS5対応が必要だった項目のまとめ(全部ではないけど)。印象として、追加された機能以上に既存ライブラリの仕様がそこそこ変わっていて、テストして発見の繰り返しだった。
以下トピック別対応の一覧。

removeFromSuperlayerの付近で落ちる

removeFromSuperlayerによりlayerのretainCountが減少するタイミングが変わった模様で、
それまではautorelease?だったっぽいが、即座にreleaseされてしまっているようだった。
以下のようにもともとのコードが悪かったので、removeFromSuperlayerを最後にするように修正。

  • 修正前のダメなコード (removeFromSuperlayerを最後にすればよい)
[aLayer removeFromSuperlayer];
[mutableArray addObject:aLayer];

この他にも、オブジェクトのリリースタイミングが変更になっているものがありそう。iOS5で突然落ちる場合は、該当箇所のオブジェクトのrelease関連に着目するとよいかもです。

ナビゲーションバーの背景色が反映されない

これはナビゲーションバーのviewの構造が変わったため。
以下のように修正。

if([navigationBar respondsToSelector:@selector(setBackgroundImage:forBarMetrics:)] ) {
        //iOS 5
        [navigationBar setBackgroundImage:image forBarMetrics: UIBarMetricsDefault];
} else {
        //iOS 4
        [navigationBar insertSubview:[[[UIImageView alloc] initWithImage:image] autorelease] atIndex:0];
}

UIAlertViewの継承クラスで、UIパーツの位置がずれる

これはlayoutSubviewsメソッドをオーバーライドしている場合で、このメソッドが1回の表示に何回もコールされることで発生。ここでのUIパーツの指定座標を固定とすることで対応可能。iOSのマイナーバージョンアップでもちょくちょく変更するので、ここは本当に面倒。

旧端末(iPhone3G, iPodTouch2nd)での動作のための設定追加が必要

Xcode4.2からビルド設定のデフォルトで、アーキテクチャーがarmv7のみとなっており、旧端末でも動作させたい場合armv6の設定を追加する必要あり。動作可能なiOSバージョンを4.3以下にしていると、ビルド時におこられる。(ただし、warningのみでBUILD SUCESSとなってしまう。。。)

修正方法は以下のサイトに詳しく載ってます。
ただし、armv6のビルドではバグがあるので後方の項目(旧世代端末だけ正常に動作しない)の設定も合わせてする必要があります。

CoreDataのデータ型Integer16が厳密に

iOS4系では、CoreDataのデータ型に対してInteger16を指定してもInteger32と同じ範囲で値を利用できたけど、iOS5より、厳密にInteger16、つまり、正の場合65535が上限値になってしまい、それを超えるとマイナスに。。
もともと指定してた方が悪いけど、修正が必要。なお、sqliteをDocuments以下に配置してる場合には、データのマイグレーションが必要なので注意。

デバイスID(UDID)の利用が禁止に

UDIDがdeprecatedになり、代わりにUUIDを使えと。。(代わりにならない)
アプリ上そこまで重要でなかったので、UDIDを利用する機能ごと削除しました。

参考にUUIDの取得方法は以下に記載。

http://d.hatena.ne.jp/mmasashi/20111011/1318349518

デフォルトコンパイラApple LLVMになってコンパイルが通らない (2011/11/9追加)

Xcode4.2になってから選択可能なコンパイラが代わり、しかもデフォルトのコンパイラApple LLVM Compiler 2.0になってしまったようで、それではコンパイルが通らないということに。。
コンパイラに依存した実装があるのか、とりあえずGCC LLVM 4.2の方を選択することで回避できたので、詳細な調査は後日ということに。

この話題に関しては、以下のリンク先で詳細な説明が書かれており、参考になります。

ただ、将来的にはXcode4.2デフォルトの、Apple LLVM Compiler系が標準になりそうなので、近いうちに対応しなくてはと思ってます。

旧世代端末だけ正常に動作しない機能(or画面)がある (armv6) (2011/11/9追加)(2011/11/23追記)

上記の旧世代で動作させるarmv6をビルドアーキテクチャに含める対応で、実際に旧世代端末(iPodTouch第二世代、iPhone3G)で動作確認を行ったところ、一部正常に動作しない箇所がありました。
デバッグしていくと、ビルドタイプがDebugでは正常に動作しており、Releaseではうまくいかず、つまりはビルド時のコンパイラの最適化でしくっているということ。。armv7やsimulatorでは問題ないことから、armv6の場合だけのバグということっぽい。
なお、コンパイラGCC LLVM 4.2を利用してます。

対応としては、ビルド設定でその機能に該当するソースのみコードの最適化をしないオプション(-O0)を付与することで解決。旧端末のサポートはコストが高い。。

追記:2011/11/23

以下の記事によると、どうやらXcode4.2とarmv6の組み合わせでビルドすると、浮動小数点のバグがあるらしい。。これってかなり致命的なんじゃ。。

うちの会社で話題になったんだけど、Xcode 4.2 + armv6デバイスの組み合わせで、浮動小数点の演算にバグがあるらしい。演算結果が正しくないときがあるらしい。

なお、この場合の対応としては、リンク先の通り、設定ファイルでOther C Flagsの項目で、armv6のアーキテクチャーに対してのみ「-mno-thumb」をたてるとよいそうな。バグの内容からしてもこちらの対応にした方がよいです。


同期フォルダ(Documentsディレクトリ)にDLデータ等大容量データを置いてはいけない(2011/11/23追加)

iOS5公開とともに新しくなった審査ガイドラインのデータストレージに関する項目のこと。これはかなりきつい制約で、iOS5でDocumentsディレクトリ以下は、iCloudバックアップ(同期)対象となり、iCloudへの負担となるため大容量のファイルをバックアップ対象にしてはいけないというもの。
対策としては、以下のリンク先に記載されているように、大容量ファイル(DLファイル)についてはバックアップされないディレクトリに配置するか、バックアップ対象ディレクトリの中で、バックアップ対象外とする属性をファイルに付与(iOS5.0.1以降対応)するかの2択だそうです。
バックアップ対象外にする弊害は、iOSのリストアやOSアップデート時にすべてそれらのデータがリセットされてしまうことで、実装者のみならずユーザにとってもかなり厳しい。。実装者視点では、配信したDLがいつ消えるかわからないのでいつでも再配信可能な仕組みを用意しておく必要があります。Documents以下に大容量のファイルを置いてオフラインで活用するアプリの場合は、この対応はかなりクリティカル。
(たくさんのアプリがこの審査ガイドライン項目でリジェクトされているらしい。。)

UILabel、UIWebView等で半角文字の幅が狭く(2011/11/29追加)

iOS4に比べて、iOS5では半角文字や半角スペースの入った文字の幅が微妙に違い、iOS5の方がより詰めて表示されるようになっていた。また、表示幅(Frameの幅)の折り返しも、iOS5の方がよりぎりぎりまで表示できるようになっており(全角1文字程度多く入る)、文字列の整形を改行等で行っている場合には、iOS4iOS5とで見た目が違ってくるので注意。

iOS3からiOS4の時には文字の高さが変わって困ったが、iOS5以降も同様のことがありそうなので、本当に厳密に調整したい場合には、独自で文字のレンダリングをする必要がありそうです。

SSL(https)のサイトにアクセスできない(2011/12/18追加)

作っているアプリで、iOS5https通信(SSL)が出来なくなってしまった。
原因を探っていくと、iOS5になってからセキュリティ関連のライブラリがアップデートされ、デフォルトのSSLのセキュリティレベルがTLS1.2になったためっぽい。(TLS1.0)

以下関連すると思われるライブラリ。

  • NSURLConnection
  • MPMoviePlayerController (<- 今回該当)
  • UIWebview

今回自分のところで問題になったのは、MPMoviePlayerControllerで一部サーバの動画を再生できないというもの(エラーも出なかった)で、原因はサーバ側がTLS1.0までしか対応していなく、かつTLSの再交渉(TLSのバージョンが合わない場合の再接続)がサポートされていないため。なお、サーバのTLSレベルや再交渉がサポートされているかどうかは、chromで簡単に調べられる。Chromeで実際にそのURLを開いて、鍵のマークをクリックするとセキュリティレベル等の詳細が出てくるのでここを見ればOK。
以下はmixiの例。(再交渉サポートなし)

MPMoviePlayerControllerの場合、この回避方法はまだ見つからず。。orz
より低レイヤの通信APIを使っている場合は、以下のAppleのテクニカルノートにある通り、SSLレベルの設定を変更することで対応が可能だけれど、MPMoviePlayerControllerでは通信をいじれないないため、それができない。今のところサーバ側を再交渉対応するアップデートを行うぐらい。

ASIHTTPRequestで出来ない場合はこちらの記事を参考。理由は同じっぽい。

エキスパートObjective-Cプログラミング ?iOS/OS Xのメモリ管理とマルチスレッド?

エキスパートObjective-Cプログラミング ?iOS/OS Xのメモリ管理とマルチスレッド?

よくわかるiPhoneアプリ開発の教科書【Xcode 4対応版】

よくわかるiPhoneアプリ開発の教科書【Xcode 4対応版】