安路的技术博客

Nothing in life is to be feared. It is only to be understood

适配iOS10

| Comments

UICOllecitonViewCell的优化

在ios10之前,UIcollectionView上面如果有大量的Cell,当用户活动很快的时候,整个UIcollectionView有很卡顿,为什么会造成这样的问题,这里涉及到iOS系统的重用机制,当cell准备加载进到屏幕的时候,整个cell都已经加载完成,等待在屏幕外面了,也就是整整一行cell都已经加载完毕,这就是造成卡顿的主要原因,专业术语叫掉帧

iOS10之前的UIcollectionViewCell的生命周期是这样的:

  1. 用户滑动屏幕,屏幕外有一个cell准备加载进来,把cell从reusr队列拿出来,然后调用prepareForReuse方法,在这个方法里面,可以重置cell的状态,加载新的数据
  2. 继续欢动,就会调用cellForItemAtIndexPath方法,在这个方法里面给cell赋值模型,然后返回给系统
  3. 当cell马上进去屏幕的时候,就会调用willDispalyCell方法,在这个方法里面我们还可以修改cell,为进入屏幕做最后的准备工作
  4. 执行完willDisplayCell方法后,cell就进去屏幕了,当cell完全离开屏幕之后,会调用didEndDisplayingCell方法

ios 10 UIcollectionViewCell的生命周期是这样的

  1. 用户滑动屏幕,屏幕外有一个cell准备加载进来,把cell从reusr队列拿出来,然后调用prepareForReuse方法,在这里当cell还没有进去屏幕的时候,就已经提前调用这个方法了,对比之前的区别就是cell的上边缘拿上进去屏幕的时候就会调用该方法,而ios10提前到cell还在屏幕外面的时候就调用
  2. 在cellForItemAtIndexPath中创建cell,填充数据,刷新状态等操作,相比之前也提前了
  3. 用户继续滑动的话,当cell马上就需要显示的时候我们再调用willDisplayCell方法,原则就是:何时需要显示,何时再去调用willDisplayCell方法
  4. 当cell完全离开屏幕以后,会调用didEndDispalyingCell方法,跟之前一样,cell会进入重用队列

在ios10之前,cell只能从重用队列里面取出,再走一遍生命周期,并调用cellForItemAtIndexPath创建或者生成一个cell.

在ios10中,系统cell会保存一段时间,也就是说当用户把cell滑出屏幕以后,如果又滑动回来,cell不用再走一遍生命周期了,只需要调用willDisplayCell方法就可以重现出现在屏幕中了。

ios10新增加的Pre-Fetching预加载

这个是为了降低UIcollectionViewCell在加载的时候所花费的时间,在iOS10中,除了数据源协议和代理协议外,新增加了一个UIcollectionViewDataSourcePrefetching协议,这个协议里面定义了两个方法:

这个是为了降低UIcollectionViewCell在加载的时候所花费的时候,在iOS10中,除了数据源协议和代理协议外,新增加了一个UIcollectionViewDataSourcePrefetching协议,这个协议里面定义了两个方法:

1
2
3
- (void)collectionView:(UICollectionView *)collectionView prefetchItemsAtIndexPaths:(NSArray *)indexPaths NS_AVAILABLE_IOS(10_0);

- (void)collectionView:(UICollectionView *)collectionView cancelPrefetchingForItemsAtIndexPaths:(NSArray *)indexPaths  NS_AVAILABLE_IOS(10_0);

在CollectionView prefetchItemAt indexPaths这个方法是异步预加载数据的,当中的indexPaths数组是有序的,就是Item接收数据的顺序: ColletionView cancelPrefetchingForItemsAt indexPaths这个方法是可选的,可以用来处理在滑动中取消或者降低提前加载数据的优先级。 这个协议并不能代替之前读取数据的方法,仅仅是辅助加载数据

UIRefreshControl的使用

在iOS10中,UIRefreshControl 可以直接在UIcollectionView和UITableView中使用,并且脱离了UITableViewController,现在RefreshControl是UIScrollView的一个属性。

使用方法:

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

关于ATS的问题

WWDC2015提出的ATS(App Transport Security)是Apple在推进网络通讯安全的一个重要的方式,在iOS9中,默认情况下非HTTPS的网络访问是被禁止的。当然,因为这样的推进影响面非常广,作为缓冲,我们可以在info.plist中添加NSAppTransportSecurity字典并且将NSAllowsArbitraryLoads设置为YES来禁用ATS.相信大家已经对这个非常熟悉了。

不过在WWDC2016中,Apple表示将继续在ios10和macOS 10.12里收紧对普通http的访问限制。从2017年一月一日起,所有的提交的app默认是不允许使用NSAllowsArbitraryLoads来绕过ATS限制的,也就是说,我们最好保证app的所有的网络请求都是HTTPS加密的,否则可能会在应用审核时遇到麻烦。

  1. 默认情况下你的app可以访问加密足够强(TLS v1.2以上,AES-128和SHA-2)的HTTPS内容,这对所有的网络请求都有效,包括NSURLSession,UIWebview以及WkWebView
  2. 你依然可以添加NSAllowsArbitraryLoadsYES来禁用ATS,不过如果你这么做的话,需要在提交app时进行说明,为什么需要访问非HTTPS的内容,一般来说,可能类似浏览器类的app比较容易能通过
  3. 相比于使用NSAllowsArbitraryLoads将全部HTTP内容放开,选择使用NSExceptionDomains来针对特定的域名开放HTTP应该要相对容易过审核。“需要访问的域名是第三方服务器,他们没有进行HTTPS对应”,会是审核时的一个可选理由,但是这应该只需要针对特定域名,而非全面开放,如果访问的是自己的服务器的话,可能这个理由会无法通过
  4. 对于网页浏览和视频播放的行为,iOS10中新加入了NSAllowsArbitraryLoadsInWebContent键,通过将它设置为YES,可以让你的app中的WKWebView和使用AVFoundation播放的在线视频不受ATS的限制。这也应该是绝大多数使用了相关特性的app的选择。但是坏消息是这个键在ios9中并不会起到作用

总结:对于API请求,基本上必须使用HTTPS的,特别是如果你们自己可以管理服务器的话,可能需要后端的同学尽快升级到HTTPS.如果你的app只支持iOS10,并且有用户可以自由输入网址进行浏览的功能,或者是在线视频音频播放功能的话,简单地加入NSAllowsArbitraryLoadsInWebContent并且将组件换成WKWebKit或者AVFoundation就可以了。如果你还需要支持ios9,并且需要访问网页和视频的话,可能只能开启NSAllowsArbitraryLoads然后提交的时候进行说明,并且看Apple审核员的脸色决定让不让通过了。除了WKWebKit以外,另外一个访问网页的选择是使用SFSafariViewController。因为其实SFSafariViewController就是一个独立于App的Safari进程,所以它完全不受ATS限制

另外,当NSAllowsArbitraryLoadsNSAllowsArbitraryLoadsInWebContent同时存在时,根据系统不同,表现的行为也会不一样,简单说,ios9只看NSAllowsArbitraryLoads,而ios10会先看NSAllowsArbitraryLoadsInWebContent.在ios10中,要是NSAllowsArbitraryLoadsInWebContent存在的话,就忽略掉NSAllowsArbitraryLoads,如果它不存在,则遵循NSAllowsArbitraryLoads的设定。

Comments