iOS工程如何支持64-bit

蘋果在2014年10月20號發(fā)布了一條消息:從明年的二月一號開始登淘,提交到App Store的應(yīng)用必須支持64-bit惭等。詳細(xì)消息地址為:https://developer.apple.com/news/?id=10202014a

那們我們應(yīng)該如何開始著手讓自己的App支持64-Bit呢取劫?

基本知識

從iPhone 5S的A7 CPU開始到剛剛發(fā)布的iPhone 6(A8 CPU)都已經(jīng)支持64-bit ARM 架構(gòu)豁陆。關(guān)于64-bit的介紹詳見維基百科镐牺。知乎上有很多關(guān)于蘋果使用A7蜓斧,A8芯片的討論,可以參考 iPhone 6 的 Apple A8 芯片對比 Apple A7 提升明顯嗎侥袜?, iPhone 5s 配備的 A7 處理器是 64 位蝌诡,意味著什么?

  • Xcode 5.0.1開始支持編譯32-bit和64-bit的Binary
  • 同時支持32-bit和64-bit,我們需要選擇的minimum deployment target為 iOS 5.1.1
  • 64-bit的Binary必須運(yùn)行在支持64-bit的CPU上枫吧,并且最小的OS版本要求是 7.0.3

關(guān)于Xcode “Build Setting”中的Architectures參數(shù)問題

  • Architectures:你想支持的指令集浦旱。(支持指令集是通過編譯生成對應(yīng)的二進(jìn)制數(shù)據(jù)包實(shí)現(xiàn)的,如果支持的指令集數(shù)目有多個九杂,就會編譯出包含多個指令集代碼的數(shù)據(jù)包颁湖,造成最終編譯的包很大。)
  • Valid architectures:即將編譯的指令集例隆。(Valid architectures 和 Architecture兩個集合的交集為最終編譯生成的版本)
  • Build Active Architecture Only:是否只編譯當(dāng)前設(shè)備適用的指令集(如果這個參數(shù)設(shè)為YES甥捺,使用iPhone 6調(diào)試,那么最終生成的一個支持ARM64指令集的Binary镀层。一般在DEBUG模式下設(shè)為YES镰禾,RELEASE設(shè)為NO)

關(guān)于指令集如下參考:

ARMv8/ARM64: iPhone 6(Plus), iPhone 5s, iPad Air(2), Retina iPad Mini(2,3)
ARMv7s: iPhone 5, iPhone 5c, iPad 4
ARMv7: iPhone 3GS, iPhone 4, iPhone 4S, iPod 3G/4G/5G, iPad, iPad 2, iPad 3, iPad Mini
ARMv6: iPhone, iPhone 3G, iPod 1G/2G

對于支持64-bit,我們可以設(shè)置Architectures為 Standard architectures,在最新的Xcode 6上,它包括 armv7和arm64吴侦。

讓App支持32-bit和64-bit基本步驟

  • 確保Xcode版本號>=5.0.1
  • 更新project settings, minimum deployment target >= 5.1.1
  • 改變Architectures為 Standard architectures(include 64-bit)
  • 運(yùn)行測試代碼谷饿,解決編譯warnings and errors,對照本文檔或者官方文檔 64-Bit Transition Guide for Cocoa Touch對相應(yīng)地方做出修改妈倔。(編譯器不能告訴我們一切)
  • 在真實(shí)的64-bit機(jī)器上測試
  • 使用Instruments查看內(nèi)存使用問題

64-bit主要的變化

64-bit運(yùn)行時環(huán)境和32-bit運(yùn)行時環(huán)境主要有以下兩點(diǎn)的不同:

  • 數(shù)據(jù)類型的改變
  • 方法調(diào)用上的改變

整型數(shù)據(jù)類型的變化如下:


關(guān)于字節(jié)對齊的概念可以參考如下鏈接:http://blog.csdn.net/21aspnet/article/details/6729724#comments
浮點(diǎn)型類型的改變?nèi)缦?

數(shù)據(jù)類型的改變可能會為我們的程序帶來這些影響:

  • 增加內(nèi)存壓力
  • 64-bit到32-bit數(shù)據(jù)之間的相互轉(zhuǎn)化
  • 計(jì)算可能產(chǎn)生不同的結(jié)果
  • 當(dāng)把一個值從大的數(shù)據(jù)類型拷貝到小的數(shù)據(jù)類型,數(shù)據(jù)可能被截?cái)喑窆薄#∟SInteger -> int

方法調(diào)用上的改變
基于32-bit的CPU和基于64-bit上的CPU有不同數(shù)量的寄存器盯蝴,在方法調(diào)用上有不同的協(xié)議。因此32-bit和64-bit在匯編層級上是不同的听怕。如果我們在程序中不使用匯編編程捧挺,調(diào)用協(xié)議很少會遇到。

如何編寫健壯的64-bit代碼

根據(jù)上述改變尿瞭,官方文檔 64-Bit Transition Guide for Cocoa Touch給出如下7步:

  • 不要將長整型long賦值給整型int (64-bit上會導(dǎo)致數(shù)據(jù)丟失)
  • 不要將指針類型pointer賦值給整型int (64-bit導(dǎo)致地址數(shù)據(jù)丟失)
  • 留意數(shù)值計(jì)算(掩碼計(jì)算,無符號整數(shù)和有符號整數(shù)同時使用等)
  • 留意對齊方法帶來的變化
  • 32-bit到64-bit之間數(shù)據(jù)轉(zhuǎn)化(通過網(wǎng)絡(luò)傳遞的用戶數(shù)據(jù)闽烙,可能同時存在于32-bit和64-bit的環(huán)境下)
  • 重寫匯編代碼
  • 不要在可變參數(shù)方法和不可變參數(shù)方法之前進(jìn)行強(qiáng)制轉(zhuǎn)化

在LLVM編譯器中,枚舉類型也可以定義枚舉的大小声搁。我們在使用中黑竞,指派枚舉值到一個變量時,應(yīng)該使用適當(dāng)?shù)臄?shù)據(jù)類型疏旨。

不要將指針類型pointer賦值給整型int

<pre><code>
int a = 5;
int c = &a;
/
32-bit下正常很魂,64-bit下錯誤。最新的Xcode6.0編譯提示警告:'Cast to int* for smaller integer type int'/
int d = (int )((int)c + 4);
/
正確, 指針可以直接增加
/
int d = c + 1;
</pre></code>
如果我們一定要把指針轉(zhuǎn)化為整型檐涝,可以把上述代碼改為
<pre><code>
/
32-bit和64-bit都正常遏匆。
/
int *d = (int *)((uintptr_t)c + 4); </pre></code>
查看uintptr_t定義為 typedef unsigned long uintptr_t;

保持?jǐn)?shù)據(jù)類型一致

方法使用時,入?yún)⑺瘢鰠⒑唾x值都需要注意保持?jǐn)?shù)據(jù)類型一致幅聘。在iOS App中尤其要注意以下幾個類型的正確使用:

  • long
  • NSInteger
  • CFIndex
  • size_t

在32-bit和64-bit下,fpos_t和off_t都是64 bits的數(shù)據(jù)大小窃植,永遠(yuǎn)不要把它們指向int整型帝蒿。
<pre><code>
long PerformCalculation(void);
int c = PerformCalculation(); // 錯誤 64-bit上數(shù)據(jù)將被截取
long y = PerformCalculation(); // 正確

int PerformAnotherCalculation(int input);
long i = LONG_MAX;
int x = PerformCalculation(i); // 錯誤

int ReturnMax()
{
return LONG_MAX; // 錯誤
} </pre></code>

Cocoa中常見的數(shù)據(jù)類型轉(zhuǎn)化問題

NSInteger : 在32-bit和64-bit下有分別的定義:

<pre><code>
'#if LP64 || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
typedef long NSInteger;
'#else
typedef int NSInteger;
'#endif
</pre></code>

我們永遠(yuǎn)不應(yīng)該假設(shè)NSInteger和int是一樣大的,下面的例子在使用中就需要注意:

  • 使用NSNumber對象轉(zhuǎn)化時
  • 使用NSCoder編解碼的時候撕瞧,如果在64-bit設(shè)備下對NSInteger編碼陵叽,在32-bit設(shè)備下對NSInteger解碼。解碼時如果值的大小超過了32-bit丛版,這個時候就會出現(xiàn)異常
  • Famework中使用NSInteger定義的一些常量

CGFloat: 和NSInteger一樣有不同的定義
<pre><code>
typedef CGFLOAT_TYPE CGFloat;
'#if defined(LP64) && LP64
'# define CGFLOAT_TYPE double
'#else
'# define CGFLOAT_TYPE float
'#endif
</pre></code>

下面給出錯誤示范:
<pre><code>
CGFloat value = 200.0;
CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &value); //64-bit下出現(xiàn)錯誤
CGFloat value = 200.0;
CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &value); //正確 </pre></code>

整型數(shù)值計(jì)算問題

關(guān)于C語言的符號位擴(kuò)展可參考資料為:http://blog.163.com/shi_shun/blog/static/237078492010651063936/

我們直接來看例子:
<pre><code>
int a = -2;
unsigned int b = 1;
long c = a + b;
long long d = c;
printf("%lld\n", d); </pre></code>
問題:這段代碼在32-bit下運(yùn)行結(jié)果符合我們的預(yù)期巩掺,輸出為 -1(0xffffffff)。在64-bit下運(yùn)行結(jié)果為:4294967295 (0x00000000ffffffff)页畦。

原因:一個有符號的值和一個同樣精度的無符號的值相加結(jié)果是無符號的胖替。這個無符號的結(jié)果被轉(zhuǎn)換到更高精度的數(shù)值上時采用零擴(kuò)展。

解決方案:把變量b換成長整型long

創(chuàng)建數(shù)據(jù)結(jié)構(gòu)時使用合適的數(shù)據(jù)大小

C99提供了內(nèi)置的數(shù)據(jù)類型保證了一致的數(shù)據(jù)大小,即使底層的硬件結(jié)構(gòu)不同独令。在某些case下端朵,我們知道數(shù)據(jù)是一個固定的大小或者一個特定的變量擁有一個有限的取值范圍。這個時候燃箭,我們應(yīng)該選擇特定的類型以避免浪費(fèi)內(nèi)存冲呢。

類型如下:


永遠(yuǎn)不要使用malloc去為變量申請?zhí)囟▋?nèi)存的大小,改為使用sizeof來獲取變量或者結(jié)構(gòu)體的大小招狸。

另外我們還需要注意修改格式化字符串來同時支持32-bit和64-bit敬拓。


小心處理方法和方法指針

<pre><code>
int fixedFunction(int a, int b);
int variadicFunction(int a, ...);
int main
{
int value2 = fixedFunction(5,5);
int value1 = variadicFunction(5,5);
}
</pre></code>

上述兩個方法中,在32-bit下使用相同的指令讀取參數(shù)的數(shù)據(jù)裙戏,但是在64-bit上乘凸,是使用完全不同的協(xié)議來編譯的。

如果在代碼中傳遞方法指針累榜,應(yīng)該保證方法調(diào)用的協(xié)議是一致的营勤。永遠(yuǎn)不要將一個可變參數(shù)的方法轉(zhuǎn)化成固定參數(shù)的方法。
<pre><code>
int MyFunction(int a, int b, ...);
int (action)(int, int, int) = (int ()(int, int, int)) MyFunction;
action(1,2,3); // 錯誤示范 </pre></code>

上述錯誤的寫法壹罚,編譯器是不會提示警告或者錯誤的葛作,并且在模擬器中也不會暴露出問題來。在發(fā)布自己的App前渔嚷,一定記得要使用真機(jī)去測試进鸠。

總結(jié)

在支持64-bit過程中,應(yīng)該按照Apple文檔中提供的7個步驟完整檢查項(xiàng)目工程形病。如果工程中涉及到大量的C或者C++代碼客年,在支持64-bit中要更加謹(jǐn)慎。

寫完這篇筆記后漠吻,我覺得需要重溫一下C的基礎(chǔ)知識量瓜。XD,順便祈禱項(xiàng)目中的第三方庫趕緊更新支持64-bit途乃,阿彌陀佛绍傲。

ps: 找出不支持arm64的靜態(tài)庫 find . -name *.a -exec lipo -info "{}" ;

轉(zhuǎn)載自:http://chun.tips/blog/2014/10/21/iosgong-cheng-ru-he-zhi-chi-64-bit/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市耍共,隨后出現(xiàn)的幾起案子烫饼,更是在濱河造成了極大的恐慌,老刑警劉巖试读,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件杠纵,死亡現(xiàn)場離奇詭異,居然都是意外死亡钩骇,警方通過查閱死者的電腦和手機(jī)比藻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門铝量,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人银亲,你說我怎么就攤上這事慢叨。” “怎么了务蝠?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵拍谐,是天一觀的道長。 經(jīng)常有香客問我馏段,道長赠尾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任毅弧,我火速辦了婚禮,結(jié)果婚禮上当窗,老公的妹妹穿的比我還像新娘够坐。我一直安慰自己,他們只是感情好崖面,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布元咙。 她就那樣靜靜地躺著,像睡著了一般巫员。 火紅的嫁衣襯著肌膚如雪庶香。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天简识,我揣著相機(jī)與錄音赶掖,去河邊找鬼。 笑死七扰,一個胖子當(dāng)著我的面吹牛奢赂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播颈走,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼膳灶,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了立由?” 一聲冷哼從身側(cè)響起轧钓,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎锐膜,沒想到半個月后毕箍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡枣耀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年霉晕,在試婚紗的時候發(fā)現(xiàn)自己被綠了庭再。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡牺堰,死狀恐怖拄轻,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情伟葫,我是刑警寧澤恨搓,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站筏养,受9級特大地震影響斧抱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜渐溶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一辉浦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧茎辐,春花似錦宪郊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至依啰,卻和暖如春乎串,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背速警。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工叹誉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人闷旧。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓桂对,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鸠匀。 傳聞我的和親對象是個殘疾皇子蕉斜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容