1.系统判断方法失效:

在你的项目中,当需要判断系统版本的话,不要使用下面的方法:


1. ​​#define([[[[UIDevice]]:1]]>=10)​​

它会永远返回​​NO​​​,​​substringToIndex:1​​​在iOS 10 会被检测成 iOS 1了,
应该使用下面的这些方法:
Objective-C 中这样写:


1. ​​#define(v)([[[UIDevice]]:v options:NSNumericSearch]==NSOrderedSame)​​
2. ​​#define(v)([[[UIDevice]]compare:v options:NSNumericSearch]==NSOrderedDescending)​​
3. ​​#define(v)([[[UIDevice]systemVersion]:v options:NSNumericSearch]!=NSOrderedAscending)​​
4. ​​#define(v)([[[UIDevice]]:v options:NSNumericSearch]==NSOrderedAscending)​​
5. ​​#define(v)([[[UIDevice]systemVersion]:v options:NSNumericSearch]!=NSOrderedDescending)​​

或者使用:


1. ​​if([[NSProcessInfo]:(NSOperatingSystemVersion){.majorVersion =9,.minorVersion =1,.patchVersion =0}]){​​
2. ​​// 代码块​​
3. ​​}​​
4. ​​if([NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){9,3,0}]){​​
5. ​​// 代码块​​
6. ​​}​​

或者使用:


1. ​​if(NSFoundationVersionNumber>NSFoundationVersionNumber_iOS_9_0){​​
2. ​​// 代码块​​
3. ​​}else{​​
4. ​​// 代码块​​
5. ​​}​​

有时候会缺少一些常量,​​NSFoundationVersionNumber​​​是在​​NSObjCRuntime.h​​​中定义的,作为Xcode7.3.1的一部分,我们设定常熟范围从iPhone OS 2到​​#define NSFoundationVersionNumber_iOS_8_4 1144.17​​,在iOS 10(Xcode 8)中,苹果补充了缺少的数字,设置有未来的版本.


1. ​​#defineNSFoundationVersionNumber_iOS_9_01240.1​​
2. ​​#defineNSFoundationVersionNumber_iOS_9_11241.14​​
3. ​​#defineNSFoundationVersionNumber_iOS_9_21242.12​​
4. ​​#defineNSFoundationVersionNumber_iOS_9_31242.12​​
5. ​​#defineNSFoundationVersionNumber_iOS_9_41280.25​​
6. ​​#defineNSFoundationVersionNumber_iOS_9_x_Max1299​​

Swift中这样写:


1. ​​ifNSProcessInfo().isOperatingSystemAtLeastVersion(NSOperatingSystemVersion(majorVersion:10,minorVersion:0,:0)){​​
2. ​​// 代码块​​
3. ​​}​​

或者使用


1. ​​if#available(iOS 10.0, *) { ​​
2. ​​// 代码块​​
3. ​​}else{​​
4. ​​// 代码块​​
5. ​​}​​

2.隐私数据访问问题:

你的项目中访问了隐私数据,比如:相机,相册,联系人等,在Xcode8中打开编译的话,统统会crash,控制台会输出下面这样的日志:

这是因为iOS对用户的安全和隐私的增强,在申请很多私有权限的时候都需要添加描述,但是,在使用Xcode 8之前的Xcode还是使用系统的权限通知框.
要想解决这个问题,只需要在​​​info.plist​​​添加​​NSContactsUsageDescription​​的key, value自己随意填写就可以,这里列举出对应的key(Source Code模式下):


1. ​​<!-- 相册 -->​​
2. ​​<key>NSPhotoLibraryUsageDescription</key>​​
3. ​​<string>App需要您的同意,才能访问相册</string>​​
4. ​​<!-- 相机 -->​​
5. ​​<key>NSCameraUsageDescription</key>​​
6. ​​<string>App需要您的同意,才能访问相机</string>​​
7. ​​<!-- 麦克风 -->​​
8. ​​<key>NSMicrophoneUsageDescription</key>​​
9. ​​<string>App需要您的同意,才能访问麦克风</string>​​
10. ​​<!-- 位置 -->​​
11. ​​<key>NSLocationUsageDescription</key>​​
12. ​​<string>App需要您的同意,才能访问位置</string>​​
13. ​​<!-- 在使用期间访问位置 -->​​
14. ​​<key>NSLocationWhenInUseUsageDescription</key>​​
15. ​​<string>App需要您的同意,才能在使用期间访问位置</string>​​
16. ​​<!-- 始终访问位置 -->​​
17. ​​<key>NSLocationAlwaysUsageDescription</key>​​
18. ​​<string>App需要您的同意,才能始终访问位置</string>​​
19. ​​<!-- 日历 -->​​
20. ​​<key>NSCalendarsUsageDescription</key>​​
21. ​​<string>App需要您的同意,才能访问日历</string>​​
22. ​​<!-- 提醒事项 -->​​
23. ​​<key>NSRemindersUsageDescription</key>​​
24. ​​<string>App需要您的同意,才能访问提醒事项</string>​​
25. ​​<!-- 运动与健身 -->​​
26. ​​<key>NSMotionUsageDescription</key><string>App需要您的同意,才能访问运动与健身</string>​​
27. ​​<!-- 健康更新 -->​​
28. ​​<key>NSHealthUpdateUsageDescription</key>​​
29. ​​<string>App需要您的同意,才能访问健康更新 </string>​​
30. ​​<!-- 健康分享 -->​​
31. ​​<key>NSHealthShareUsageDescription</key>​​
32. ​​<string>App需要您的同意,才能访问健康分享</string>​​
33. ​​<!-- 蓝牙 -->​​
34. ​​<key>NSBluetoothPeripheralUsageDescription</key>​​
35. ​​<string>App需要您的同意,才能访问蓝牙</string>​​
36. ​​<!-- 媒体资料库 -->​​
37. ​​<key>NSAppleMusicUsageDescription</key>​​
38. ​​<string>App需要您的同意,才能访问媒体资料库</string>​​

如果不起作用,可以请求后台权限,类似于这样:


1. ​​<key>UIBackgroundModes</key>​​
2. ​​<array>​​
3. ​​<!-- 在这里写上你在后台模式下要使用权限对应的key -->​​
4. ​​<string>location</string>​​
5. ​​...​​
6. ​​</array>​​

或者在Xcode里选中当前的​​target​​​,选择​​Capabilities​​​,找到​​Background Modes​​,打开它,在里面选择对应权限

3.UIColor的问题

官方文档中说:大多数​​core​​​开头的图形框架和​​AVFoundation​​​都提高了对扩展像素和宽色域色彩空间的支持.通过图形堆栈扩展这种方式比以往支持广色域的显示设备更加容易。现在对UIKit扩展可以在sRGB的色彩空间下工作,性能更好,也可以在更广泛的色域来搭配sRGB颜色.如果你的项目中是通过低级别的api自己实现图形处理的,建议使用sRGB,也就是说在项目中使用了RGB转化颜色的建议转换为使用sRGB,在​​UIColor​​类中新增了两个api:


1. ​​-(UIColor*)initWithDisplayP3Red:(CGFloat)displayP3Red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha NS_AVAILABLE_IOS(10_0);​​
2. ​​+(UIColor*)colorWithDisplayP3Red:(CGFloat)displayP3Red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha NS_AVAILABLE_IOS(10_0);​​

4.真彩色的显示

真彩色的显示会根据光感应器来自动的调节达到特定环境下显示与性能的平衡效果,如果需要这个功能的话,可以在​​info.plist​​里配置(在Source Code模式下):


1. ​​<key>UIWhitePointAdaptivityStyle</key>​

它有五种取值,分别是:


1. ​​<string>UIWhitePointAdaptivityStyleStandard</string> // 标准模式​​
2. ​​<string>UIWhitePointAdaptivityStyleReading</string> // 阅读模式​​
3. ​​<string>UIWhitePointAdaptivityStylePhoto</string> // 图片模式​​
4. ​​<string>UIWhitePointAdaptivityStyleVideo</string> // 视频模式​​
5. ​​<string>UIWhitePointAdaptivityStyleStandard</string> // 游戏模式​​

也就是说如果你的项目是阅读类的,就选择​​UIWhitePointAdaptivityStyleReading​​这个模式,五种模式的显示效果是从上往下递减,也就是说如果你的项目是图片处理类的,你选择的是阅读模式,给选择太好的效果会影响性能.

5.ATS的问题

1.在iOS 9的时候,默认非HTTS的网络是被禁止的,我们可以在​​info.plist​​​文件中添加​​NSAppTransportSecurity​​​字典,将​​NSAllowsArbitraryLoads​​​设置为​​YES​​​来禁用ATS;
2.从2017年1月1日起,,所有新提交的 app 默认不允许使用​​​NSAllowsArbitraryLoads​​​来绕过ATS的限制,默认情况下你的 app 可以访问加密足够强的(TLS V1.2以上)HTTPS内容;
3.可以选择使用​​​NSExceptionDomains​​设置白名单的方式对特定的域名开放HTTP内容来通过审核,比如说你的应用集成了第三方的登录分享SDK,可以通过这种方式来做,下面以新浪SDK作为示范(Source Code 模式下):


1. ​​<key>NSAppTransportSecurity</key>​​
2. ​​<dict>​​
3. ​​<key>NSExceptionDomains</key>​​
4. ​​<dict>​​
5. ​​<key>sina.cn</key>​​
6. ​​<dict>​​
7. ​​<key>NSThirdPartyExceptionMinimumTLSVersion</key>​​
8. ​​<string>TLSv1.0</string>​​
9. ​​<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>​​
10. ​​<false/>​​
11. ​​<key>NSIncludesSubdomains</key>​​
12. ​​<true/>​​
13. ​​</dict>​​
14. ​​<key>weibo.cn</key>​​
15. ​​<dict>​​
16. ​​<key>NSThirdPartyExceptionMinimumTLSVersion</key>​​
17. ​​<string>TLSv1.0</string>​​
18. ​​<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>​​
19. ​​<false/>​​
20. ​​<key>NSIncludesSubdomains</key>​​
21. ​​<true/>​​
22. ​​</dict>​​
23. ​​<key>weibo. com</key>​​
24. ​​<dict>​​
25. ​​<key>NSThirdPartyExceptionMinimumTLSVersion</key>​​
26. ​​<string>TLSv1.0</string>​​
27. ​​<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>​​
28. ​​<false/>​​
29. ​​<key>NSIncludesSubdomains</key>​​
30. ​​<true/>​​
31. ​​</dict>​​
32. ​​<key>sinaimg.cn</key>​​
33. ​​<dict>​​
34. ​​<key>NSThirdPartyExceptionMinimumTLSVersion</key>​​
35. ​​<string>TLSv1.0</string>​​
36. ​​<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>​​
37. ​​<false/>​​
38. ​​<key>NSIncludesSubdomains</key>​​
39. ​​<true/>​​
40. ​​</dict>​​
41. ​​<key>sinajs.cn</key>​​
42. ​​<dict>​​
43. ​​<key>NSThirdPartyExceptionMinimumTLSVersion</key>​​
44. ​​<string>TLSv1.0</string>​​
45. ​​<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>​​
46. ​​<false/>​​
47. ​​<key>NSIncludesSubdomains</key>​​
48. ​​<true/>​​
49. ​​</dict>​​
50. ​​<key>sina.com.cn</key>​​
51. ​​<dict>​​
52. ​​<key>NSThirdPartyExceptionMinimumTLSVersion</key>​​
53. ​​<string>TLSv1.0</string>​​
54. ​​<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>​​
55. ​​<false/>​​
56. ​​<key>NSIncludesSubdomains</key>​​
57. ​​<true/>​​
58. ​​</dict>​​
59. ​​</dict>​​
60. ​​</dict>​​

4.在iOS 10 中​​info.plist​​​文件新加入了​​NSAllowsArbitraryLoadsInWebContent​​​键,允许任意web页面加载,同时苹果会用 ATS 来保护你的app;
5.安全传输不再支持​​​SSLv3​​​, 建议尽快停用​​SHA1​​​和​​3DES​​算法;

6.UIStatusBar的问题:

在iOS10中,如果还使用以前设置UIStatusBar类型或者控制隐藏还是显示的方法,会报警告,方法过期,如下图:

上面方法到 iOS 10 不能使用了,要想修改UIStatusBar的样式或者状态使用下图中所示的属性或方法:

    1. ​​@property(nonatomic,readonly)UIStatusBarStyle(7_0)__TVOS_PROHIBITED;// Defaults to UIStatusBarStyleDefault​​
    2. ​​@property(nonatomic,readonly)(7_0)__TVOS_PROHIBITED;// Defaults to NO​​
    3. ​​-(UIStatusBarStyle)preferredStatusBarStyle NS_AVAILABLE_IOS(7_0);// Defaults to UIStatusBarStyleDefault​​
    4. ​​-(BOOL)prefersStatusBarHidden NS_AVAILABLE_IOS(7_0);// Defaults to NO​​
    5. ​​// Override to return the type of animation that should be used for status bar changes for this view controller. This currently only affects changes to prefersStatusBarHidden.​​
    6. ​​-(UIStatusBarAnimation)preferredStatusBarUpdateAnimation NS_AVAILABLE_IOS(7_0)__TVOS_PROHIBITED;// Defaults to UIStatusBarAnimationFade​​

    7.UITextField

    在iOS 10 中,​​UITextField​​​新增了​​textContentType​​​字段,是​​UITextContentType​​​类型,它是一个枚举,作用是可以指定输入框的类型,以便系统可以分析出用户的语义.是电话类型就建议一些电话,是地址类型就建议一些地址.可以在​​#import <UIKit/UITextInputTraits.h>​​​文件中,查看​​textContentType​​字段,有以下可以选择的类型:


    1. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeName(10_0);​​
    2. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeNamePrefix(10_0);​​
    3. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeGivenName(10_0);​​
    4. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeMiddleName(10_0);​​
    5. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeFamilyName(10_0);​​
    6. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeNameSuffix(10_0);​​
    7. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeNickname(10_0);​​
    8. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeJobTitle(10_0);​​
    9. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeOrganizationNameNS_AVAILABLE_IOS(10_0);​​
    10. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeLocation(10_0);​​
    11. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeFullStreetAddressNS_AVAILABLE_IOS(10_0);​​
    12. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeStreetAddressLine1NS_AVAILABLE_IOS(10_0);​​
    13. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeStreetAddressLine2NS_AVAILABLE_IOS(10_0);​​
    14. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeAddressCity(10_0);​​
    15. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeAddressState(10_0);​​
    16. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeAddressCityAndStateNS_AVAILABLE_IOS(10_0);​​
    17. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeSublocality(10_0);​​
    18. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeCountryName(10_0);​​
    19. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypePostalCode(10_0);​​
    20. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeTelephoneNumberNS_AVAILABLE_IOS(10_0);​​
    21. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeEmailAddress(10_0);​​
    22. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeURL(10_0);​​
    23. ​​UIKIT_EXTERN UITextContentTypeconstUITextContentTypeCreditCardNumberNS_AVAILABLE_IOS(10_0);​​

    8.UserNotifications(用户通知)

    iOS 10 中将通知相关的 API 都统一了,在此基础上很多用户定义的通知,并且可以捕捉到各个通知状态的回调.以前通知的概念是:大家想接受的提前做好准备,然后一下全两分发,没收到也不管了,也不关心发送者,现在的用户通知做成了类似于网络请求,先发一个​​request​​​得到​​response​​​的流程,还封装了​​error​​​,可以在各个状态的方法中做一些额外的操作,并且能获得一些字段,比如发送者之类的.这个功能的头文件是:​​#import <UserNotifications/UserNotifications.h>​​主要有以下文件:


    1. ​​#import <UserNotifications/NSString+UserNotifications.h>​​
    2. ​​#import <UserNotifications/UNError.h>​​
    3. ​​#import <UserNotifications/UNNotification.h>​​
    4. ​​#import <UserNotifications/UNNotificationAction.h>​​
    5. ​​#import <UserNotifications/UNNotificationAttachment.h>​​
    6. ​​#import <UserNotifications/UNNotificationCategory.h>​​
    7. ​​#import <UserNotifications/UNNotificationContent.h>​​
    8. ​​#import <UserNotifications/UNNotificationRequest.h>​​
    9. ​​#import <UserNotifications/UNNotificationResponse.h>​​
    10. ​​#import <UserNotifications/UNNotificationSettings.h>​​
    11. ​​#import <UserNotifications/UNNotificationSound.h>​​
    12. ​​#import <UserNotifications/UNNotificationTrigger.h>​​
    13. ​​#import <UserNotifications/UNUserNotificationCenter.h>​​
    14. ​​#import <UserNotifications/UNNotificationServiceExtension.h>​​

    9.UICollectionViewCell的的优化

    在iOS 10 之前,UICollectionView上面如果有大量cell,当用户活动很快的时候,整个UICollectionView的卡顿会很明显,为什么会造成这样的问题,这里涉及到了iOS 系统的重用机制,当cell准备加载进屏幕的时候,整个cell都已经加载完成,等待在屏幕外面了,也就是整整一行cell都已经加载完毕,这就是造成卡顿的主要原因,专业术语叫做:掉帧.
    要想让用户感觉不到卡顿,我们的app必须帧率达到60帧/秒,也就是说每帧16毫秒要刷新一次.

    iOS 10 之前UICollectionViewCell的生命周期是这样的:
    • 1.用户滑动屏幕,屏幕外有一个cell准备加载进来,把cell从reusr队列拿出来,然后调用​​prepareForReuse​​方法,在这个方法里面,可以重置cell的状态,加载新的数据;
    • 2.继续滑动,就会调用​​cellForItemAtIndexPath​​方法,在这个方法里面给cell赋值模型,然后返回给系统;
    • 3.当cell马上进去屏幕的时候,就会调用​​willDisplayCell​​方法,在这个方法里面我们还可以修改cell,为进入屏幕做最后的准备工作;
    • 4.执行完​​willDisplayCell​​​方法后,cell就进去屏幕了.当cell完全离开屏幕以后,会调用​​didEndDisplayingCell​​方法.
    iOS 10 UICollectionViewCell的生命周期是这样的:
    • 1.用户滑动屏幕,屏幕外有一个cell准备加载进来,把cell从reusr队列拿出来,然后调用​​prepareForReuse​​方法,在这里当cell还没有进去屏幕的时候,就已经提前调用这个方法了,对比之前的区别是之前是cell的上边缘马上进去屏幕的时候就会调用该方法,而iOS 10 提前到cell还在屏幕外面的时候就调用;
    • 2.在​​cellForItemAtIndexPath​​中创建cell,填充数据,刷新状态等操作,相比于之前也提前了;
    • 3.用户继续滑动的话,当cell马上就需要显示的时候我们再调用​​willDisplayCell​​​方法,原则就是:何时需要显示,何时再去调用​​willDisplayCell​​方法;
    • 4.当cell完全离开屏幕以后,会调用​​didEndDisplayingCell​​​方法,跟之前一样,cell会进入重用队列.
      在iOS 10 之前,cell只能从重用队列里面取出,再走一遍生命周期,并调用​​​cellForItemAtIndexPath​​​创建或者生成一个cell.
      在iOS 10 中,系统会cell保存一段时间,也就是说当用户把cell滑出屏幕以后,如果又滑动回来,cell不用再走一遍生命周期了,只需要调用​​​willDisplayCell​​​方法就可以重新出现在屏幕中了.
      iOS 10 中,系统是一个一个加载cell的,二以前是一行一行加载的,这样就可以提升很多性能;
    iOS 10 新增加的Pre-Fetching预加载
    • 这个是为了降低UICollectionViewCell在加载的时候所花费的时间,在 iOS 10 中,除了数据源协议和代理协议外,新增加了一个​​UICollectionViewDataSourcePrefetching​​协议,这个协议里面定义了两个方法:


    1. ​​-(void)collectionView:(UICollectionView*)collectionView prefetchItemsAtIndexPaths:(NSArray<NSIndexPath*>*)indexPaths NS_AVAILABLE_IOS(10_0);​​
    2.
    3. ​​-(void)collectionView:(UICollectionView*)collectionView cancelPrefetchingForItemsAtIndexPaths:(NSArray<NSIndexPath*>*)indexPaths NS_AVAILABLE_IOS(10_0);​​

    在​​ColletionView prefetchItemsAt indexPaths​​​这个方法是异步预加载数据的,当中的​​indexPaths​​​数组是有序的,就是item接收数据的顺序;
    ​​​CollectionView cancelPrefetcingForItemsAt indexPaths​​​这个方法是可选的,可以用来处理在滑动中取消或者降低提前加载数据的优先级.
    注意:这个协议并不能代替之前读取数据的方法,仅仅是辅助加载数据.
    Pre-Fetching预加载对UITableViewCell同样适用.

    10. UIRefreshControl的使用

    在iOS 10 中, UIRefreshControl可以直接在UICollectionView和UITableView中使用,并且脱离了UITableViewController.现在RefreshControl是UIScrollView的一个属性.
    使用方法:


    1. ​​UIRefreshControl*refreshControl =[[UIRefreshControl]];​​
    2. ​​[refreshControl addTarget:self:@selector(loadData)forControlEvents:UIControlEventValueChanged];​​
    3. ​​collectionView.refreshControl =;​​

     

    注意:去除警告信息

     

    #pragma mark - UITableViewDataSources
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wunused-variable"
    int unusedInt;
    #pragma clang diagnostic pop

      NSString *str;
    #pragma unused(str)

    // 添加警告的两种方式

    #pragma message "This is a warning"

    #warning "This is another warning"

        return 10;
    }