iOS支援arm64

來源:互聯網
上載者:User

標籤:style   blog   http   ar   io   os   使用   sp   for   

Apple要求2015/2/1之後提交的包必須包含arm64,否則要被拒。因此,對於64-bit的支援可謂迫在眉睫,尤其是對於有很多遺留代碼的項目,更要提早開工。

如何支援arm64

為了支援arm64結構,需要滿足一下幾個條件:

  • 在Architectures設定項裡添加arm64條目,如果使用的Xcode是6.0以上的版本,使用預設的配置項即可。
  • 在Valid Architectures設定項裡添加arm64條目。
  • 講Deployment Target改為大於等於5.1.1即可,因為arm64最低支援5.1.1系統。
  • 支援64-bit的運行時環境,也即開啟針對64-bit的編譯器警告和錯誤,可以協助你順利地遷移到arm64。如果設定完成後沒有明顯地提示升級Xcode編譯配置項,可以先build一下code,第一條警告就是建議支援64-bit的運行時環境,enable該設定項即可。

完成這些步驟之後,就可以build一個同時包含32-bit和64-bit的IPA檔案。build完成之後你會發現有成千上百的警告和錯誤,這時候才是真正工作的開始。

另外,經過以上步驟之後,會發現當前的項目無法通過Xcode在iOS6以下的系統上聯調,或者iTunes等直接安裝打包的IPA檔案。不過將打包的IPA檔案通過AppStore發布是可以安裝在iOS5.1.1上的,有人推斷AppStore會對提交的IPA檔案做一些magic的事情。如果想在iOS6以下的系統上聯調,則需要在Valid Architectures裡去掉arm64。

arm64適配

根據Apple官方介紹,arm64會帶來以下的改變:

  • Data Type.
  • Function Calling.
  • ARM Instruction.

下面分別介紹這三方面的具體變化。

Data Type

arm64帶來的最大改變就是定址空間和寄存器從32-bit增長為64-bit,系統可以提供更多的記憶體和更大的寄存器空間。下面兩張圖列出了轉移到64-bit後Data Type的變化。

 

ILP32表示32-bit系統,LP64表示64-bit系統。圖中的黑體表示64-bit相對於32-bit的不同,其改變可以概括為以下幾點:

  • 指標的大小從4Byte增長為8Byte。
  • long,NSIteger,size_t,time_t,CFIndex,CGFloat都從4Byte增長為8Byte。
  • long long,fpos_t,off_t,double的對齊都從4Byte增長為8Byte。

從以上總結可知,如果同時為32-bit和64-bit的系統開發軟體,不可避免地會在32-bit和64-bit的資料之間產生運算和賦值等操作。面臨的風險主要有以下:

  • 32-bit和64-bit資料之間的操作。

    這裡的操作包括數學運算和賦值等運算,運算過程中可能會遇到資料截斷,資料的溢出以及一些獨特的邊界情況。主要有以下幾種情況:

    • 32-bit和64-bit資料之間的賦值。將一個64-bit的資料賦給一個32-bit的變數,比如:

      int intValue = NSItegerMax;

      這將會導致資料截斷,並不會得到期望的結果。同理如果將一個32-bit的資料賦給一個64-bit的變數,將會獲得意想不到的結果,比如:

      NSUInteger biggerIntValue = -1;
    • 指向32-bit資料的指標變數和指向64-bit資料的指標變數互相賦值。如下操作:

      int *pointerToInt = pointerToLong;pointerToLong = pointerToInt;

      由於pointerToInt + 1實際上是+4,而pointerToLong + 1實際上是+8,所以轉換之後再進行指標運算所得結果是錯的。

    • 指標和變數之間的賦值。如下:

      int currentAddress = pointerToLong;NSInteger *pointerToNSInteger = currentAddress + 1;

      這裡的指標地址不但被截斷了,並且+1操作也不會得到期望的結果。

    • 隱式的枚舉類型轉換。編譯器會為每個枚舉類型分配一個合適的儲存類型,可能是int也可能是NSInteger,根據其需要分配。因此,隱式地將枚舉類型賦給其他類型的變數時,可能導致資料被截斷,或者被錯誤地提升。
    • 與系統相關的資料類型。NSIntegerMax在32-bit和64-bit所表示的值是不一樣大地。另外代碼中常見的hardCode也存在問題,比如左移操作中常見的32,24等。

    針對以上列出的潛在風險,這裡有兩點建議:

    1. 使用相同的資料類型。盡量減少顯式和隱式類型轉換,使用相同的資料類型。
    2. 避免在指標與整形之間互相轉換。盡量避免將指標賦給轉型變數,或者顯式地強制轉換。如果真的需要,請使用uintptr_t類型。
  • 在32-bit和64-bit的軟體之間交換資料。

    32-bit和64-bit的軟體很可能通過網路讀寫同一份檔案,甚至使用者也會用32-bit軟體的資料覆蓋64-bit軟體下的同一份資料,這些都會導致無法預測地錯誤。比如NSInteger在32-bit是4Byte,而在64-bit上則是8Byte。如果這時在32-bit軟體裡訪問由64-bit軟體產生的內容為NSInteger類型的檔案,結果無法預測。

     struct second {     int milliSecond;     long microSecond; };
    在32-bit軟體中second的大小為8Byte,microSecond的位移量為4。而在64-bit軟體中second的大小為16Byte,而microSecond得位移量為8。如果這是在32-bit和64-bit系統中持久化改模型或者將其傳到網路上供其他軟體訪問,將不會得到正確的結果。 針對這個問題,這裡提供一些建議:
    1. 使用一致的資料類型。

      也即盡量使用與系統無關的資料類型,如果該軟體同時存在32-bit和64-bit的版本,建議在32-bit和64-bit中使用相同的資料類型。比如,不管在32-bit軟體還是64-bit軟體上,盡量都使用int32_t或者int64_t。

    2. 建立記憶體模型一致的資料模型。

      即資料模型大小和其中的元素位移量都相同。針對上面提到的第二個問題,有以下兩種解決方案:

       struct second { int32_t milliSecond; int32_t microSecond; };   #pagram pack(4) struct second { int32_t milliSecond; int64_t microSecond; }; #pragma options align=reset
    3. 使用plist,XML和JSON進行序列化和持久化。

      當使用NSCoder在64-bit軟體上encode一個NSInteger資料,而後在32-bit軟體上decode該NSInteger資料,同時該整型數值正好超出了32-bit int類型可以表示的範圍時,將會拋出一個異常。

  • 消耗更多的記憶體。

    由以上的分析可知,很多的基本類型和指標地址都從4Byte增長為8Byte,這也預示著64-bit軟體將消耗更多的記憶體。不但一些基本類型消耗了更多的記憶體,甚至常用的Foundation Object都要消耗更多的記憶體,由於其強大的功能,比如NSArray,NSDictionary。針對這個問題有以下幾點建議:

    • 選用合適的Foundation Object。

      如果在NSArray裡只儲存一個簡單的對象,然後產產生千上百這也的對象,那麼消耗的記憶體將是巨大的。因此,盡量在合適的場合使用合適的類。

    • 選擇緊湊的資料模型。

      盡量選擇更合適的資料模型來表示你的資料。假定你要表示一個date類型,使用的資料模型如下:

        struct date {      NSInteger second;      NSInteger minute;      NSInteger hour;      NSInteger day;      NSInteger month;      NSInteger year;  };

      在32-bit的軟體上date的大小是24Byte,在64-bit的軟體上date是48Byte,驚人吧!簡單地改變一下設計,在達到目標的同時還可以節省很多的記憶體使用量,結構如下:

        struct date {  long seconds;  };

      seconds表示流逝的總秒數,通過簡單的計算即可得到year,month,day......

    • 消除多餘的padding。

      為了效能的原因,編譯器通常會在基礎資料型別 (Elementary Data Type)之間添加padding,以使他們對齊,避免多次訪問記憶體。比如:

         struct morePadding {    //32-bit       char second;         //offset 0       int  minute;         //offset 4       char hour;           //offset 8       NSInteger day;       //offset 12   };                     //total size 16

      morePadding的實際大小為10Byte,而佔據的記憶體大小為16Byte。經過重新設計將其改為以下結構:

         struct morePadding {    //32-bit       int  minute;         //offset 0       NSInteger day;       //offset 4       char second;         //offset 8       char hour;           //offset 9   };                     //total size 10
    • 使用盡量少的指標變數。

      避免在資料模型中過度使用指標,考慮以下模型:

         struct node{         node        *previous;         node        *next;         uint32_t    value;       };

      在64-bit軟體中node總大小為20Byte,而有效資料只有4Byte,80%的空間都被指標佔據,可以考慮使用其他的資料結構代替。

    • 在可以表達的範圍內使用更小的資料類型。

      如果只是表達幾千幾百的數字,則int就可以滿足需求了,不需要使用NSInteger。宗旨就是使用夠用的資料類型表示數字,沒有必要64-bit軟體就一定要使用int64_t類型。

    • 只cache必須的資料。

      為了效能最佳化的目的,我們的代碼經常使用cache機制,即拿空間換時間,cache確實可以在很多地方提高軟體的響應速度,甚至節省網路流量等。比如緩衝網狀圖片避免下次連網,緩衝經過濾鏡處理以後的圖片,避免CPU多次執行同意操作。64-bit軟體消耗了更多的記憶體,如果緩衝了過多的無關緊要的東西,可能反而會降低軟體的整體效能。因此,建議以下的情況不要使用緩衝:

      • 可以容易地重新計算產生的。
      • 很容易從其他地方擷取的。
      • 廉價地重建的。
      • 唯讀資料可以通過mmap()訪問的。

      所以,應該經常地測試cache確實提升了效能。

    • 合理使用@autoreleasepool。

      儘快釋放不再需要的autorelease對象,避免記憶體耗盡迫使系統發出UIApplicationDidReceiveMemoryWarningNotification通知。尤其是for迴圈和遞迴調用的場合,需要給出特別的關注。

    • 處理UIApplicationDidReceiveMemoryWarningNotification。

      所有相關的對象都必須處理UIApplicationDidReceiveMemoryWarningNotification通知,尤其是各個Controller,cache Manager需要第一時間響應該通知,避免導致低記憶體的crash。

Function calling

如果沒有使用組合語言的話,轉換到64-bit的影響並不是很大,只有一點,可變參數的函數的調用規則在64-bit軟體上是不一樣的。因此,對於函數調用建議如下:

  • 實參和形參使用一致的資料類型。
  • 避免在函數簽名不一樣的函數之間強制轉換。

    在不同的函數簽名的指標變數之間互相傳遞,很容易導致調用函數的時候傳遞不合適的參數,從而無法得到預期的結果,尤其在固定參數的函數和可變參數的函數之間強制轉換,如下所示:

      int MyFunction(int a, int b, ...);  int (*action)(int, int, int) = (int (*)(int, int, int)) MyFunction; action(1,2,3); // Error!
  • 給可變參數的函數傳遞正確的參數。

    由於可變參數列表通常未提供類型資訊,如果這時傳遞了錯誤的參數值,將不會得到正確的結果。所以,可以考慮給可變參數添加格式字串,提供一定的類型資訊,比如printf()

Objective-C Runtime

不要直接存取OC對象的isa,在64-bit軟體裡邊isa不再是一個指向class object的指標,它包含一些指標資料和一些運行時資訊。如果需要得到class object,使用object_getClass函數。

ARM64 Instruction

arm64的指令極大地不同於32-bit的指令,因此,彙編代碼需要重寫。arm64的函數呼叫慣例跟標準的arm不太一樣,可以參考iOS ABI Function Call Guide。

iOS支援arm64

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.