關於iOS和OS X廢棄的API知識點

来源:http://www.cnblogs.com/wujy/archive/2016/04/29/5445546.html
-Advertisement-
Play Games

今天在查看蘋果介面文檔時,突然對於介面的聲明知識點比較感興趣,再網路找到下麵這個比較不錯的文章,記錄一下並分享; 如你所知,已廢棄(Deprecated)的API指的是那些已經過時的並且在將來某個時間最終會被移除掉的方法或類。通常,蘋果在引入一個更優秀的API後就會把原來的API給廢棄掉。因為,新引 ...


今天在查看蘋果介面文檔時,突然對於介面的聲明知識點比較感興趣,再網路找到下麵這個比較不錯的文章,記錄一下並分享;

 

如你所知,已廢棄(Deprecated)的API指的是那些已經過時的並且在將來某個時間最終會被移除掉的方法或類。通常,蘋果在引入一個更優秀的API後就會把原來的API給廢棄掉。因為,新引入的API通常意味著可以更好的發揮新硬體或操作系統的性能,或者可以使用一些在構建原有API時根本還沒有的語言特性(e.g. blocks)。

每當蘋果添加新方法的時候,他們都會在方法聲明的後面用一個很特殊的巨集來標明哪些iOS版本支持它們。例如,在UIViewController中,蘋果引入了一個使用block來處理回調的方法用來展示一個模態controller,它的聲明是這樣的

- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^)(void))completion NS_AVAILABLE_IOS(5_0);

註意到NS_AVAILABLE_IOS(5_0)了嗎?這就告訴我們這個方法可以在iOS5.0及以後的版本中使用。如果我們在比指定版本更老的版本中調用這個方法,就會引起崩潰。

那被這個方法替換了的那個舊方法又怎麼樣了呢?同樣,它的聲明後面也帶了一個類似的語法,表示它已經被廢棄了:

- (void)presentModalViewController:(UIViewController *)modalViewController animated:(BOOL)animated NS_DEPRECATED_IOS(2_0, 6_0);

NS_DEPRECATED_IOS(2_0, 6_0)這個巨集中有兩個版本號。前面一個表明瞭這個方法被引入時的iOS版本,後面一個表明它被廢棄時的iOS版本。被廢棄並不是指這個方法就不存在了,只是意味著我們應當開始考慮將相關代碼遷移到新的API上去了。

還有類似形式的一些巨集用在iOS和OS X共用的類上。比如NSArray中的這個方法:

- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx NS_AVAILABLE(10_8, 6_0);

這裡的NS_AVAILABLE巨集告訴我們這方法分別隨Mac OS 10.8和iOS 6.0被引入。和NS_DEPRECATED_IOS類似,也有個巨集叫NS_DEPRECATED,但它的參數要稍微複雜些:

- (void)removeObjectsFromIndices:(NSUInteger *)indices numIndices:(NSUInteger)cnt NS_DEPRECATED(10_0, 10_6, 2_0, 4_0);

這裡表示這個方法隨Mac OS 10.0和iOS 2.0被引入,在Mac OS 10.6和iOS 4.0後被廢棄。

Easy Come, Easy Go

上周我們討論了在iOS7和Mac OS 10.9 SDK中被新引入的Base64 API。有趣的是,有一組有相同功能的Base64方法,在被引入的同時也被廢棄掉了。為什麼蘋果在引入一個API的同時又把它廢棄掉了?那不是毫無意義的嗎?好吧,其實也不是——它在下麵這種情況下就非常有意義:

實際上,這些現在已經廢棄的Base64方法從iOS4和Mac 0S 10.6開始就一直存在,只是它們是私有的。直到現在蘋果才把它們公開,大概是蘋果一直對它們的實現不滿意,一直都想把它們改寫。

果然,在iOS7中,蘋果選定了一個他們感到滿意的Base64 API,並且將它添加到了NSData的一個公有類別中。但現在,他們知道老方法已經被取代,不會被改寫了,因此他們把它公開出來。當開發者的app仍然需要支持iOS6及以前的版本時,就有了一個系統內置的Base64 api可以用。

這就是為什麼,如果你查看這些新API的方法聲明,可以看到NS_DEPRECATED巨集部分中的起始版本是4_0,雖然實際上直到iOS7之前,它從來都沒有被作為公有API被引入過:

- (NSString *)base64Encoding NS_DEPRECATED(10_6, 10_9, 4_0, 7_0);

這告訴你,基於iOS7 SDK開發的app如果調用了這個方法,它同樣可以運行在iOS4+或Mac OS 10.6+的系統上而不會崩潰。很有用的吧?

如何使用已廢棄的API

那麼,如果我們有一個app需要同時支持iOS6和iOS7,想用內置的Base64方法,我們該怎麼做呢?事實上,這相當簡單,你只需要調用這些廢棄的API就可以了。

那樣編譯器不是會產生警告嗎?不會——只有你的deployment target版本號設置成大於或等於方法被棄用的版本號的時候才會收到編譯器警告。只要你仍然在支持那些還沒有廢棄這個方法的iOS版本,都不會收到警告。

那麼,如果蘋果決定在iOS8中移除已棄用的Base64方法,你的應用程式會發生情況?簡單來說,它肯定會崩潰,但是不要讓這把你嚇跑了:蘋果不可能只在幾個iOS版本後就將已廢棄的API給移除(絕大多數已廢棄的API在任何的iOS版本中都還沒有被移除),除非你決定不再更新你的app,否則在你放棄支持iOS6之前有很多機會都可以更新到新的API。

但是如果假定我們在最壞的情況下(例如:我們不更新我們的app了,而蘋果突然宣佈了一個零容忍的不再向下相容的政策),怎樣讓我們的代碼保持永不過時並且仍然能夠支持舊的系統版本呢?

這其實很簡單,我們只需要做一些運行時的方法檢測。使用NSObject的respondsToSelector:方法,我們可以檢測,如果新的API存在,我們就調用它。否則,我們退回到已廢棄的API。很簡單:

NSData *someData = ...
NSString *base64String = nil;

// Check if new API is available
if ([someData respondsToSelector:@selector(base64EncodedDataWithOptions:)])
{
  // It exists, so let's call it
  base64String = [someData base64EncodedDataWithOptions:0];
}
else
{
  // Use the old API
  base64String = [someData base64Encoding];
}

此代碼在iOS4及以上版本中有效,並且如果蘋果在未來的iOS版本中移除base64Encoding方法後,同樣可以正常工作。

為其他開發者編碼的時候

如果你是在寫一個app,這一切都很好,但是如果你是在編寫一個給其他人使用的代碼庫呢?如果project的target是iOS4或iOS6的時候,上面的代碼會工作的很好。但是如果deployment target是iOS 7+的時候,你就會收到編譯器警告,說你使用了已廢棄的base64Encoding方法。

該代碼實際上永遠都可以正常工作,因為那個方法在運行時永遠都不會被調用(因為respondsToSelector:那個檢查在iOS7上總是會返回YES)。但是可惜的是,編譯器還不是足夠的聰明能發現這點。而且,比如像我,你不會想用那些會產生編譯器警告的第三方庫,你肯定也不想自己的庫中產生任何警告。

那麼,我們如何改寫我們的代碼,以便它可以用於任何deployment target,而不會產生警告?幸好,有一個編譯器巨集指令可以基於不同的deployment target做不同的代碼分支。取決於app是為哪個最小的iOS版本編譯的,我們可以用__IPHONE_OS_VERSION_MIN_REQUIRED這個巨集來生成不同的代碼。

下麵的代碼可以工作在任何的iOS版本上(不管是過去的還是將來的),而且不會產生任何警告:

#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0

// Check if new API is not available
if (![someData respondsToSelector:@selector(base64EncodedDataWithOptions:)])
{
    // Use the old API
    base64String = [someData base64Encoding];
}
else

#endif

{
    // Use the new API
    base64String = [someData base64EncodedDataWithOptions:0];
}

看清楚我們在這裡做了什麼嗎?我們變換了respondsToSelector:的用法:我們用它來測試是否新的API不可用,然後將整段代碼放到一個條件代碼塊中,這樣它就只會在deployment target比iOS7低的情況下才會被編譯。如果app是為iOS6編譯的,它就會先檢查新的API是否存在,如果不存在就調用舊的API。如果app是為iOS7編譯的,那一整塊邏輯代碼都會被跳過,直接調用新的API。

 

另外:UI_APPEARANCE_SELECTOR

@property(nullable, nonatomic, strong) UIColor *onTintColor NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR; 

iOS後屬性帶UI_APPEARANCE_SELECTOR 可以統一設置全局作用


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 以前寫過一個沉浸式狀態欄 的實現方式 Android 沉浸式狀態欄 實現方式一 現在有個更為簡單的實現方式 。 相關鏈接 http://www.apkbus.com/forum.php?mod=viewthread&tid=255929&extra=page%3D3%26filter%3Dsorti ...
  • 一、UIApplication Delegate 1、基本介紹 所有的移動操作系統都有個致命的缺點:app很容易受到打擾。比如一個來電或者鎖屏會導致app進入後臺甚至被終止。 還有很多其它類似的情況會導致app受到干擾,在app受到干擾時,會產生一些系統事件,這時UIApplication會通知它的 ...
  • android:theme="@style/AppTheme"換成android:theme="@style/Theme.AppCompat.NoActionBar" ...
  • 運行效果 ...
  • 正在看《第一行代碼》,記錄一下使用 HTTP 協議訪問網路的內容吧! 在Android發送Http請求有兩種方式,HttpURLConnection和HttpClient。 1.使用HttpURLConnection 首先要獲取到HttpURLConnection的實例,只需要new出一個URL對象 ...
  • 一.Activity組件1.簡介:Activity組件是Android四大組件之一,通常一個Activity相當於一個用戶界面,我們可以通過載入佈局文件將Android提供的各種控制項及自定義控制項顯示到用戶界面,併為其註冊監聽,來響應用戶的即時操作。2.Activity生命周期方法:①onCreate ...
  • App Store: 天的故事 一個寫故事、分享故事、閱讀故事的應用。 五彩繽紛的首頁。 故事有開端、中段、結尾,一天有上午、下午、晚上,每一天都是個完整的故事,也是個多彩的故事。 好故事要能一句話概括,天的故事只要330字,配上豐富的色彩來表現感受和心情,天的故事簡潔美觀,有趣易讀。 在這裡,你可 ...
  • 跳到健康設置 上網找了一下 你會發現很難找到。代碼如下 不信你試試 。 NSURL *url = [NSURL URLWithString:@"prefs:root=Privacy&path=HEALTH"]; if ([[UIApplication sharedApplication] canOp ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...