【iOS7】64ビット対応について調べてみた


## はじめに

iPhone5sはA7チップが採用され、世界初の64ビットスマートフォンとして話題になりました。その話を聞いて興奮された方、そうでない方、多々いらっしゃると思いますが、私は後者です(^_^; 64ビット端末が意味する事とは！？どんなお付き合いをすればいいのか！？などなどをアプリ開発者目線でざっくばらん（独断と偏見に満ちています）にまとめてみました。

## なんでこのタイミングで64ビット化したの？

64ビット化と聞いてアプリ開発者が一番想像し易いメリットはおそらく「使用できるメモリ量の上限が4GB(2GB)を超えられる」という点だと思いますが、現状まだそこまでメモリを搭載していませんし、今後発売される端末(iPhoneに限らず)にきっと大量のメモリを搭載してくるから、先攻して開発できるようにしたのかな？などと勝手に想像しています。

64ビット化の理由について他にも考察されている方がいらっしゃいますのでリンクを貼っておきます。
参考：[なぜiPhone 5sは64ビット化を果たしたのか。その効果と未来とは？（AppBankさん）](http://www.appbank.net/2013/10/27/iphone-news/690428.php)
参考：[iOS 7 が 64-bit 対応になった意味（藤 シローさん）](http://maclalala2.wordpress.com/2013/09/15/ios-7-が-64-bit-対応になった意味/)

## 64ビットに対応する必要はあるの？

今のところAppleが64ビット対応を強制していないので、64ビット対応は各自の判断に任されていますが、以下のような消極的な理由で64ビットに対応しておくべきかなと考えてはいます。

- Apple公式ドキュメント等で、パフォーマンスの向上が期待できるとしているため（ただしパフォーマンスの計測は行ってね、とのこと）。
- 64ビット端末で32ビットバイナリを実行すると、一部の標準機能が正しく動作しないため。
 - 顔認証が動作しないそうです（未検証）  
参考：[32bit/64bit同梱ファットバイナリだとAppStoreからのリリースバイナリのみiOS6で起動できなくなる問題について（いたのくまんぼうさん）](http://ninebonz.net/fat-binary)
 - Core Imageのフィルター処理でGPUではなくCPUを指定して処理させようとした時に動作しない (iOS7.0.4 + iPad Airで検証済み)。
 - GameKitのBluetooth機能を使うとログに"Bluetooth problem in 32-bit processes on 64-bit system: skipping check"と出力される（実際にどんな不具合が生じるかは不明）。
- （新規アプリの場合）将来64ビットに対応させる手間が発生するならば、後でワーキャー言うより最初から対応しておいた方が楽そうだから。

## 64ビットでビルドしたら32ビット端末で動かないんじゃないの？？？

ここが最初謎だったのですが、Xcodeで64ビット対応アプリをアーカイブすると32ビット/64ビットそれぞれのバイナリがビルドされるようです（中間言語などではなく、ネイティブコンパイルされる）。
こうして複数のCPU用のバイナリを格納したものを、一般的には「ファットバイナリ」だとか「同梱バイナリ」だとか言うようです（公式ドキュメントでは「混成バイナリ」とありますが、直訳の予感）。

Xcodeのプロジェクト設定内の「Build Settings」タブを見ますと、「Architectures（アーキテクチャーズ）」という項目があり、ここで対応させるアーキテクチャ（CPU）を指定します。

![スクリーンショット 2014-02-17 10.12.32.png](https://qiita-image-store.s3.amazonaws.com/0/31347/737d3eb8-05d6-cff2-bdb5-33b9c9334344.png "スクリーンショット 2014-02-17 10.12.32.png")

armv7はiPhone4Sなど、armv7sはiPhone5やiPhone5c、arm64はiPhone5sに積まれているCPUのアーキテクチャです。

このように複数のアーキテクチャを指定している場合、アーカイブ時にはプロジェクトがアーキテクチャごとにビルドされて、それが１つの実行バイナリファイル（ipaファイル）になるというイメージでしょうか（armv7, armv7s, arm64対応だと３回はビルドが走るって事ですね）。

ちなみにarm64アーキテクチャに対応した混成バイナリの動作条件はiOS5.1.1以降だそうです（Xcode上のドロップダウンリストには出てきませんが直接入力すると反映されるようです）。

アーキテクチャなど、あまり馴染みのない単語が出てきますが、くだけた説明が出来そうにないのでwikipediaへのリンクを貼っておきますね。
参考：[ARMアーキテクチャ (wikipedia)](http://ja.wikipedia.org/wiki/ARMアーキテクチャ)
参考：[コンピュータ・アーキテクチャ (wikipedia)](http://ja.wikipedia.org/wiki/コンピュータ・アーキテクチャ)

## 64ビットへ対応するための手順

公式日本語ドキュメントに全部載っていますのでこれに目を通して頂ければ問題ないかと思います。
参考：[Cocoa Touch 64ビット移行ガイド](https://developer.apple.com/jp/documentation/CocoaTouch64BitGuide.pdf)

32ビットから64ビットへ移行する時にハマりやすいポイントは網羅されていると思いますが、個人的に特に気にした点＆ハマった点を書いておきます。

### データ型のバイト長やアライメントが変わっている点に注意

公式ドキュメントにも書いてありますが現時点では32ビットも64ビットも両方対応させる必要がありますので、例えば32ビットー64ビット端末間で通信を行ったり、iTunes経由でバイナリファイルをやりとりする際に異なるバイト長の型を使ってしまうと酷い事になるのは明らかです。

「だったら同じバイト長の型を最初から使っていればいいじゃない！」...と考えてしまうわけなのですが、`CGFloat`の型が32ビットでは`float`型だったのが64ビットで`double`型になってしまいCoreGraphics系のすべて(?)の型のバイト長が揃いません。`CGRect`や`CGAffineTransform`ももちろんアウトです。

回避策として、あまり精度を気にしないのであればシリアライズの際に各値を`float`型へ変換して格納するといった手が使えるかと思います。

### オープンソースは修正しないと正しく動かないことも

`typedef long INT32;`
こんな感じで明らかに32ビットの整数型を宣言しているにも関わらず`long`型を使っているものは（動作はすると思いますが）バイナリファイルに値を書き出している場合は64ビット端末では誤動作する可能性があります。

必要に応じて`int`や`int32_t`に置き換えないといけません。

### objc_msgSendでクラッシュする

こちらも公式ドキュメントに症状も回避方法も書いてある内容です（参考項目：Objective-Cのメッセージはメソッド関数のプロトタイプを使ってディスパッチする）。

`[NSObject performSelector:withObject:]`を使うと警告が出るのが嫌だったり、引数が足りなかったりするため、`objc_msgSend`を使っている場合がありますが、そのままだと実機でクラッシュします（シミュレータがではクラッシュしません）。

キャストすれば回避できます。

## 終わりに

あまりコンピュータやコンパイラの仕組みに精通していないため、書いていて自信のない所が多かったです。
突っ込みはお手柔らかにお願いいたしますm(_ _)m