关于iOS和OS X废弃的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 itbase64String = [someData base64EncodedDataWithOptions:0]; } else {// Use the old APIbase64String = [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 APIbase64String = [someData base64Encoding]; } else#endif{// Use the new APIbase64String = [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 可以统一设置全局作用
关于iOS和OS X废弃的API知识点相关推荐
- 《Objective-C高级编程 iOS与OS X多线程和内存管理》读书笔记
<Objective-C高级编程 iOS与OS X多线程和内存管理>读书笔记 第一章:自动引用计数 自己生成的对象,自己所持有. 非自己生成的对象,自己也能持有 不再需要自己持有的对象时释 ...
- iOS 与OS X多线程和内存管理 笔记 ARC与所有权修饰符
注:本文为笔记形式,所以很多都是摘抄的.<<iOS 与OS X多线程和内存管理>>书中写的很棒,简单易懂,建议各位看官自己去看看. ####ARC和MRC 前一篇主要是MRC环 ...
- 苹果发布全新 iOS 及 OS X 系统,同时推出全新编程语言 Swift
苹果发布全新 OS X 10.10 Yosemite 1. 苹果今天凌晨发布了最新的 Mac 操作系统 OS X 10.10 Yosemite.Yosemite 即美国优胜美地国家公园.如此前的猜测, ...
- iOS和OS X中的bundle
bundle也可以称之为包(package). 它在iOS和OS X中实际为一个文件夹但却当成单独的文件来对待. 每一个app都有一个bundle,并且你可以通过在xxx.app图标上右击鼠标然后选择 ...
- iOS/Mac OS X 汉字转拼音
作者: ani_di 版权所有,转载务必保留此链接 http://blog.csdn.net/ani_di iOS/Mac OS X 汉字转拼音 网络流行的汉字转拼音方案是带一个拼音码表,速度快.其实 ...
- 读《编写高质量iOS与OS X代码的52个有效方法》
又看了一遍<编写高质量iOS与OS X代码的52个有效方法>这本书,做一个简单的总结,其中runtime和GCD那些的不是太详细,要想很详细估计写的东西比篇文字都多,但恰巧又是iOS的重点 ...
- 和iPhoto道别 iOS 10/OS X将有大调整
一般情况下苹果都会在每年的WWDC开发者大会上放出最新系统的预览版本,消息称在今年6月即将召开的WWDC大会上苹果会放出全新的iOS 10预览版,并且同iOS 10一同进行了挑战的还有OS X 10. ...
- 大疆Android SDK API知识点讲解及课程最终demo展示
大疆Android SDK API知识点讲解及课程最终demo展示 大疆Android SDK课程--主要讲解Android开发环境的搭建.如何连接无人机.获取摄像头信息以及如何导入高德地图到APP当 ...
- 网易163邮箱配置-iOS、OS X邮箱客户端
最近在找工作,及时收取笔试和面试通知邮件是非常有必要的,想用一个客户端同时收取foxmail邮箱和163邮箱.有人会说,用一个邮箱不就行了,干嘛自己给自己找麻烦?那么问题来了,碰上个死对头公司,像36 ...
- ios调用restful接口_Office 365 iOS SDK-如何调用SharePoint REST API
所有iOS SDK示例均提供了用于访问邮件,日历,ODfB文件的工作代码,但没有一个示例显示如何访问SharePoint列表项.因此,我正在尝试在Swift中进行一个简单的REST调用,但始终出现以下 ...
最新文章
- 编写运行最简单的java程序——使用记事本编写java程序
- 全球第五大社交网站,二号员工离职创业,自爆心酸历程!想做10亿美元规模?先活着!...
- 清理多个varnish服务器缓存的脚本
- android 入门 006(sqlite增删改查)
- Mysql:查询当天、今天、本周、上周、本月、上月、本季度、本年的数据
- Azure VNet介绍
- P3157 动态逆序对 ,树状数组套动态开点线段树
- 2017西安交大ACM小学期数据结构 [又是树状数组、异或]
- elfutils cc1: all warnings being treated as errors
- Rust是如何实现内存安全的--理解RAII/所有权机制/智能指针/引用
- 由项目中的一个小问题所联想到的。
- springBoot项目首页居然还有这么多种玩儿法,index.html并不是必须的
- 解决TextView上方空白
- 菜鸟的B4A(B4X)开发成长日志
- 计算机应不应该学电路,应该怎么学才能入门电子技术
- [課程筆記] 機器學習2021(李弘毅) L13. Transformer (下)
- element-ui 实现图标选择器
- 有50 家人家,每家一条狗。有一天警察通知
- 20200414-AMD的Ryzen5-4500U的性能对比测试(宏碁SF314(Acer)传奇 14英寸 )
- 2021-11-15