客官,您里边请~
前言:
在这说点题外话,现在到处都在说iOS寒冬来了,朋友也好、公众号、新闻都在反应一个情况,就是iOS工作不好找。确实,我知道的三个朋友今年找iOS都花了差不多两三个月。所以,在我开始找工作的时候,内心还是极其担忧的,不过,感觉自己很幸运,两天半面了四家,拿了三个offer。不过,也深深感受到招聘者的苦恼和iOS应聘者的尴尬处境。有的招聘方招一俩月都找不到一个合适的程序员,而程序员又都觉得他们要求太高或者同行太多,行情不好。各有各的担忧吧,但记住一句话,只要有实力就不要怕,现在iOS行业正在洗盘,坚持不了的、技术不好的都有可能被洗掉。所以,在我们杞人忧天的时候,我想还不如多提升一下自己。
好吧,讲了这么多废话,下面进入主题,一进公司,给分配了一个11年产的老得mac Pro,当时就有点不开心,还好,昨天给换了个新的。还要吐槽一下,公司的网真是龟速啊。下载东西就没超过100kb!额,额,好像现在说的也不是正题。好吧,然后前几天回家下了Xcode8,发现有不少坑啊,本想今天自己总结一下,发现自己的太不全面,所以就参考了网上一些大牛的(自己总结的不全面,所以还是搬运大牛们的了)。重在学技术嘛。
Xcode8的那些坑
也不能说是坑吧,就一些新特性
-
证书Signing
这个变化就比较明显了,它可以帮助我们自动的来管理证书,但我感觉却带来的麻烦反而多了,操作的不对会出现各种不同的错误。Automatically manage signing这个选项,建议勾选上哈。见网上有人总结的很全面,我就直接搬过来了。
1.Xcode未设置开发者账号情况下的截图
QQ20160913-0.png-38.5kB
解决办法是:大家在Xcode的偏好设置中,添加苹果账号,即可。
2.设备机器未添加进开发者的Device情况下的截图
QQ20160913-2.png-33.7kB
解决办法是:大家在官网将设备添加进开发机后,陪下描述文件重新下个描述文件即可。
3.正常情况:Xcode配置登录开发者账号后的图片,耐心等待即可。
QQ20160913-1.png-25.1kB
等待完成之后的图
QQ20160913-3.png-27kB
Xib文件的注意事项
使用Xcode8打开xib文件后,会出现下图的提示。
QQ20160913-9.png-41.7kB
大家选择Choose Device即可。之后大家会发现布局啊,frame乱了,只需要更新一下frame即可。如下图
QQ20160913-11.png-113.2kB
注意:如果按上面的步骤操作后,在用Xcode7打开Xib会报一下错误,
QQ20160913-12.png-32.3kB
解决办法:需要删除Xib里面
这句话,以及把< document >中的toolsVersion和< plugIn >中的version改成你正常的xib文件中的值,不过不建议这么做。
代码注释不能用的解决办法
这个是因为苹果解决xcode ghost,把插件屏蔽了。
解决方法
打开终端,命令运行: sudo /usr/libexec/xpccachectl
然后必须重启电脑后生效。
VVDocumenter-Xcode无法使用的解决办法:
使用快捷键:option + command + /
权限以及相关设置
注意,添加的时候,末尾不要有空格我们需要打开info.plist文件添加相应权限的说明,否则程序在iOS10上会出现崩溃。具体如下图:
麦克风权限:Privacy - Microphone Usage Description 是否允许此App使用你的麦克风?
相机权限: Privacy - Camera Usage Description 是否允许此App使用你的相机?
相册权限: Privacy - Photo Library Usage Description 是否允许此App访问你的媒体资料库?
通讯录权限: Privacy - Contacts Usage Description 是否允许此App访问你的通讯录?
蓝牙权限:Privacy - Bluetooth Peripheral Usage Description 是否许允此App使用蓝牙?
语音转文字权限:Privacy - Speech Recognition Usage Description 是否允许此App使用语音识别?
日历权限:Privacy - Calendars Usage Description 是否允许此App使用日历?
定位权限:Privacy - Location When In Use Usage Description 我们需要通过您的地理位置信息获取您周边的相关数据
定位权限: Privacy - Location Always Usage Description 我们需要通过您的地理位置信息获取您周边的相关数据定位的需要这么写,防止上架被拒。
推送
如下图的部分,不要忘记打开。所有的推送平台,不管是极光还是什么的,要想收到推送,这个是必须打开的哟✌️
QQ20160914-4.png
之后就应该可以收到推送了。另外,极光推送也推出新版本了,大家也可以更新下。
PS.苹果这次对推送做了很大的变化,希望大家多查阅查阅,处理推送的代理方法也变化了。
// 推送的代理[
iOS10收到通知不再是在[application: didReceiveRemoteNotification:]
方法去处理, iOS10推出新的代理方法,接收和处理各类通知(本地或者远程)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler { //应用在前台收到通知 NSLog(@"========%@", notification);}- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler { //点击通知进入应用 NSLog(@"response:%@", response);}
屏蔽杂乱无章的bug
更新Xcode8之后,新建立工程,都会打印一堆莫名其妙看不懂的Log.如这些
subsystem: com.apple.UIKit, category: HIDEventFiltered, enable_level: 0, persist_level: 0, default_ttl: 0, info_ttl: 0, debug_ttl: 0, generate_symptoms: 0, enable_oversize: 1,
屏蔽的方法如下:Xcode8里边 Edit Scheme-> Run -> Arguments, 在Environment Variables里边添加OS_ACTIVITY_MODE = Disable
QQ20160914-8.png
如果写了之后还是打印log,请重新勾选对勾,就可以解决了
Ps.考虑到添加上述内容在Xcode8后,真机调试可能出现异常,大家可以自定义一个宏定义,来做日志输出。
iOS10的适配
1.系统判断方法失效:
在你的项目中,当需要判断系统版本的话,不要使用下面的方法:
#define isiOS10 ([[[[UIDevice currentDevice] systemVersion] substringToIndex:1] intValue]>=10)
它会永远返回NO,substringToIndex:1
在iOS 10 会被检测成 iOS 1了,应该使用下面的这些方法:Objective-C 中这样写:
#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)
或者使用:
if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){
.majorVersion = 9,
.minorVersion = 1,
.patchVersion = 0
}]) {
NSLog(@"Hello from > iOS 9.1");
}if ([NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){
9,3,0
}]) {
NSLog(@"Hello from > iOS 9.3");
}
或者使用:
if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_9_0) { // do stuff for iOS 9 and newer} else { // do stuff for older versions than iOS 9}
有时候会缺少一些常量,NSFoundationVersionNumber是在NSObjCRuntime.h中定义的,作为Xcode7.3.1的一部分,我们设定常熟范围从iPhone OS 2到#define NSFoundationVersionNumber_iOS_8_4 1144.17,在iOS 10(Xcode 8)中,苹果补充了缺少的数字,设置有未来的版本.
#define NSFoundationVersionNumber_iOS_9_0 1240.1#define NSFoundationVersionNumber_iOS_9_1 1241.14#define NSFoundationVersionNumber_iOS_9_2 1242.12#define NSFoundationVersionNumber_iOS_9_3 1242.12#define NSFoundationVersionNumber_iOS_9_4 1280.25#define NSFoundationVersionNumber_iOS_9_x_Max 1299
Swift中这样写:
if NSProcessInfo().isOperatingSystemAtLeastVersion(NSOperatingSystemVersion(majorVersion: 10, minorVersion: 0, patchVersion: 0)) { // 代码块}
或者使用
if #available(iOS 10.0, *) { // 代码块} else { // 代码块}
2.隐私数据访问问题:
你的项目中访问了隐私数据,比如:相机,相册,联系人等,在Xcode8中打开编译的话,统统会crash,控制台会输出下面这样的日志:
Snip20160905_1.png
这是因为iOS对用户的安全和隐私的增强,在申请很多私有权限的时候都需要添加描述,但是,在使用Xcode 8之前的Xcode还是使用系统的权限通知框.要想解决这个问题,只需要在info.plist
添加NSContactsUsageDescription
的key, value自己随意填写就可以,这里列举出对应的key(Source Code模式下):
NSPhotoLibraryUsageDescription App需要您的同意,才能访问相册
NSCameraUsageDescription App需要您的同意,才能访问相机
NSMicrophoneUsageDescription App需要您的同意,才能访问麦克风
NSLocationUsageDescription App需要您的同意,才能访问位置
NSLocationWhenInUseUsageDescription App需要您的同意,才能在使用期间访问位置
NSLocationAlwaysUsageDescription App需要您的同意,才能始终访问位置
NSCalendarsUsageDescription App需要您的同意,才能访问日历
NSRemindersUsageDescription App需要您的同意,才能访问提醒事项
NSMotionUsageDescription App需要您的同意,才能访问运动与健身
NSHealthUpdateUsageDescription App需要您的同意,才能访问健康更新
NSHealthShareUsageDescription App需要您的同意,才能访问健康分享
NSBluetoothPeripheralUsageDescription App需要您的同意,才能访问蓝牙
NSAppleMusicUsageDescription App需要您的同意,才能访问媒体资料库
如果不起作用,可以请求后台权限,类似于这样:
或者在Xcode里选中当前的target,选择Capabilities,找到Background Modes,打开它,在里面选择对应权限
后台模式的操作.png
3.UIColor的问题
官方文档中说:大多数core
开头的图形框架和AVFoundation
都提高了对扩展像素和宽色域色彩空间的支持.通过图形堆栈扩展这种方式比以往支持广色域的显示设备更加容易。现在对UIKit扩展可以在sRGB的色彩空间下工作,性能更好,也可以在更广泛的色域来搭配sRGB颜色.如果你的项目中是通过低级别的api自己实现图形处理的,建议使用sRGB,也就是说在项目中使用了RGB转化颜色的建议转换为使用sRGB,在UIColor类中新增了两个api:
-(UIColor *)initWithDisplayP3Red:(CGFloat)displayP3Red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha
+(UIColor *)colorWithDisplayP3Red:(CGFloat)displayP3Red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha
色的显示
真彩色的显示会根据光感应器来自动的调节达到特定环境下显示与性能的平衡效果,如果需要这个功能的话,可以在info.plist
里配置(在Source Code模式下):
它有五种取值,分别是:
UIWhitePointAdaptivityStyleStandard // 标准模式UIWhitePointAdaptivityStyleReading // 阅读模式UIWhitePointAdaptivityStylePhoto // 图片模式UIWhitePointAdaptivityStyleVideo // 视频模式UIWhitePointAdaptivityStyleStandard // 游戏模式
也就是说如果你的项目是阅读类的,就选择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 模式下):
NSAppTransportSecurity
NSExceptionDomains
sina.cn NSThirdPartyExceptionMinimumTLSVersion
TLSv1.0
NSThirdPartyExceptionRequiresForwardSecrecy
NSIncludesSubdomains
weibo.cn
NSThirdPartyExceptionMinimumTLSVersion
TLSv1.0
NSThirdPartyExceptionRequiresForwardSecrecy
NSIncludesSubdomains
weibo. com
NSThirdPartyExceptionMinimumTLSVersion
TLSv1.0
NSThirdPartyExceptionRequiresForwardSecrecy
NSIncludesSubdomains
sinaimg.cn
NSThirdPartyExceptionMinimumTLSVersion
TLSv1.0
NSThirdPartyExceptionRequiresForwardSecrecy
NSIncludesSubdomains
sinajs.cn
NSThirdPartyExceptionMinimumTLSVersion
TLSv1.0
NSThirdPartyExceptionRequiresForwardSecrecy
NSIncludesSubdomains
sina.com.cn
NSThirdPartyExceptionMinimumTLSVersion
TLSv1.0
NSThirdPartyExceptionRequiresForwardSecrecy
NSIncludesSubdomains
4.在iOS 10 中info.plist
文件新加入了NSAllowsArbitraryLoadsInWebContent键,允许任意web页面加载,同时苹果会用 ATS 来保护你的app;
5.安全传输不再支持SSLv3, 建议尽快停用SHA1和3DES算法;
6.UIStatusBar的问题:
在iOS10中,如果还使用以前设置UIStatusBar类型或者控制隐藏还是显示的方法,会报警告,方法过期,如下图:
UIStatusBar的警告.png
上面方法到 iOS 10 不能使用了,要想修改UIStatusBar的样式或者状态使用下图中所示的属性或方法:
@property(nonatomic, readonly) UIStatusBarStyle preferredStatusBarStyle NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED; // Defaults to UIStatusBarStyleDefault@property(nonatomic, readonly) BOOL prefersStatusBarHidden NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED; // Defaults to NO- (UIStatusBarStyle)preferredStatusBarStyle NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED; // Defaults to UIStatusBarStyleDefault- (BOOL)prefersStatusBarHidden NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED; // Defaults to NO// 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.- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED; // Defaults to UIStatusBarAnimationFade
7.UITextField
在iOS 10 中,UITextField
新增了textContentType
字段,是UITextContentType
类型,它是一个枚举,作用是可以指定输入框的类型,以便系统可以分析出用户的语义.是电话类型就建议一些电话,是地址类型就建议一些地址.可以在#import
文件中,查看textContentType
字段,有以下可以选择的类型:
UIKIT_EXTERN UITextContentType const UITextContentTypeName NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeNamePrefix NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeGivenName NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeMiddleName NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeFamilyName NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeNameSuffix NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeNickname NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeJobTitle NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeOrganizationName NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeLocation NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeFullStreetAddress NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeStreetAddressLine1 NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeStreetAddressLine2 NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeAddressCity NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeAddressState NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeAddressCityAndState NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeSublocality NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeCountryName NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypePostalCode NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeTelephoneNumber NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeEmailAddress NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeURL NS_AVAILABLE_IOS(10_0);UIKIT_EXTERN UITextContentType const UITextContentTypeCreditCardNumber NS_AVAILABLE_IOS(10_0);
8.UserNotifications(用户通知)
iOS 10 中将通知相关的 API 都统一了,在此基础上很多用户定义的通知,并且可以捕捉到各个通知状态的回调.以前通知的概念是:大家想接受的提前做好准备,然后一下全两分发,没收到也不管了,也不关心发送者,现在的用户通知做成了类似于网络请求,先发一个request得到response的流程,还封装了error,可以在各个状态的方法中做一些额外的操作,并且能获得一些字段,比如发送者之类的.这个功能的头文件是:#import
主要有以下文件:
#import
#import
#import
#import
#import
#import
#import
#import
#import
#import
#import
#import
#import
#import
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
协议,这个协议里面定义了两个方法:
- (void)collectionView:(UICollectionView *)collectionView prefetchItemsAtIndexPaths:(NSArray *)indexPaths NS_AVAILABLE_IOS(10_0);
- (void)collectionView:(UICollectionView *)collectionView cancelPrefetchingForItemsAtIndexPaths:(NSArray *)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的一个属性.使用方法:
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init]; [refreshControl addTarget:self action:@selector(loadData) forControlEvents:UIControlEventValueChanged]; collectionView.refreshControl = refreshControl;
文/Eternaldream(作者)原文链接:http://www.jianshu.com/p/f8151d556930
文/徐不同(作者)原文链接:http://www.jianshu.com/p/9756992a35ca