IOS中多版本,多裝置類型支援注意事項
IOS系統從07年出來,到現在也有6年了,每年發布一次到兩次新的裝置,從iPhone1,iPhone2 ... iPhone4s再到最新的iPhone5。硬體在升級的過程中CPU的架構也可能發生變化,如最早的armv6,armv7再帶最新的iPhone5所以用的armv7s。同時伴隨每一次硬體升級,系統都會做一次大版本的升級,目前最新的版本已經到了6.x了。
每次系統升級的時候,總有一些使用者會因為各種原因不願或者不能升級到最新的系統。這就意味著,如果我們的程式要讓儘可能多的人使用,就得支援儘可能多的硬體架構及系統版本。如果我們寫的程式和硬體打交道比較少的話,要做的事也就是配置一下工程選項中的Architectures,在其中添加上我們要支援的硬體架構就好了。然而每次系統的升級都會伴隨這很多新的API,Framework的引入,以及部分老的API的廢棄。也就說我們要支援的系統版本越多,工作量也就越大,所以我們通常會根據工作量和系統版本的分布情況做出取捨。現在AppStore上基本上的程式一般最多也就支援IOS 4.3的系統了吧,我做的上個項目PowerCam記得也是從4.0版本開始支援。
下面我們分別從兩個方面討論一下:
一、支援多裝置類型
不同的裝置CPU指令集可能是不同的,這也就導致了其支援的架構可能不同。例如iPhone3G及之前版本的裝置的CPU只支援armv6的指令集,導致了這些裝置只支援OpenGL ES 1.1版本,所有iPad及iPhone3GS之後的所有裝置都採用armv7及armv7s(iPhone5,iPad4採用)指令集,因此既可以支援OpenGL ES 1.1和2.0。
如何設定呢? Xcode工程的targets的buildSetting中有一項Architectures,通過這一項我們設定工程所支援的裝置類型。現在最新的Xcode版本4.5在建立工程的時候,預設值是“Standard(armv7,armv7s) ”,即支援iPhone3GS之後的所有裝置。如果你寫的程式需要支援iPhone3G的話,則需要編輯該選項,點擊該選項選擇others即可編輯,添加上armv6即可。如所示:
二、支援多系統版本
Xcode在工程的編譯選項中,我們可以看到兩個選項:Base SDK和Deployment Target,第一個選項是用來設定我們項目是基於哪個版本的SDK開發,第二選項是用來設定我們的項目最低可以部署到哪一個系統運行。
Xcode建立的工程中通常都會採用最用的SDK以及支援到最新的版本。因為我們要既支援新的版本,同事兼顧的老的版本,為了能夠利用上新版本中新的特性,所以最好選擇最新的SDK,這一項通常不用改,維持原樣就好。如果要支援叫早的系統版本,則需要修改Deployment Target選項。如所示,我們設定項目需要最老的版本為IOS 4.3。
到這兒就設定完了,Xcode會根據我們的設定進行編譯打包。在這裡我們討論一下Xcode是如何使用了最新版本的SDK,卻可以支援到較老的系統版本呢?查閱文檔SDK Compatibility Guide發現,在程式打包的時候,Xcode只是將一些匯出符號打到我們的程式包中,具體到運行時會根據實際的裝置的系統版本進行匹配。文檔中有一個圖可以解釋Base SDK和Deployment Target之間是如何運作的,如:
該圖是以Mac OS工程為例的,不過原理是一樣的。意思是對於我們支援部署的版本之前的所有API,我們都是可以無條件使用的(當前在新的版本中最好使用新的API),在我們支援部署的版本和我們開發所基於的SDK版本之間的API,能否使用取決於我們的APP具體啟動並執行系統版本。
在系統版本升級的過程中,通常會添加一些新的API和Framework,也會廢棄掉一些舊的效率不高的API。這些廢棄的API雖然不能立馬變得不可用,但是不保證在後面的版本中會繼續支援,所以為了我們的程式能夠在新的系統中更可靠,高效的運行,我們應該盡量使用新的API。
無論是在新的系統版本中調用已經不支援了的API,還是在舊的系統版本中調用新的系統版本中才引入的API都會導致我們的程式Crush。因此我們在調用那些我們部署的版本以後添加的API或者Framework時需要進行判斷當前程式所啟動並執行環境是否支援。
下面我們從幾個方面討論:
1) 判斷一個類是否可用
在IOS 4.2以後我們可以通過class這個類方法來判斷一個類在當前運行時是否可用,代碼如下:
if ([UICollectionView class]) { // 6.0以後可以使用 } else { // 之前的版本,需要使用可替代的技術實現 }
在Mac OS則需要使用NSClassFromString來判斷一個類是否可用。
2) 判斷一個方法是否可用
NSObject類有一個方法instancesRespondToSelector可以用來判斷一個類的執行個體是否響應指定的方法,如果要判斷一個類是否響應一個類方法則可以使用respondToSeletor方法。代碼如下:
if ([UIViewController instancesRespondToSelector:@selector(presentViewController:animated:completion:)]) { // 5.0以後支援 } else { // 不支援該方法 }
3) 判斷一個函數是否可用
我們知道C語言中每個函數名都代表著這個函數的地址,因此我們可以通過判斷該函數名字是否NULL來判斷支援該函數。
if (CGColorCreateCopyWithAlpha != NULL) { // 支援該函數 } else { // 不支援該函數 }
4) 判斷一個extern 變數或者Notification名是否可用
extern變數和Notification名其實都是一個變數,我們只需要判斷它的地址是否NULL即可,代碼如下:
if (&MPMoviePlayerReadyForDisplayDidChangeNotification != NULL) { // 6.0以後存在該通知 } else { // 不存在該通知 }
該文檔中還講到如果你想針對不同的SDK版本進行條件編譯,可以採用宏來實現,感興趣的同學可以自己看看。
至此,多版本多裝置類型支援注意事項就介紹完了,希望對大家能有協助。
參考文檔: SDK Compatibility Guide
註:轉載請註明出處!歡迎大家加我QQ 1592232964,一起討論共同進步。