iOS性能优化技巧

互联网上有太多关于“优化”的文章。 通过阅读这些文章,我一直在研究。 在这里,我想分享一些技巧,您可以从哪里开始优化应用程序。

调整点是;

  1. 触感
  2. WebView中的触摸响应度
  3. 应用启动时间
  4. 减少影像资源
  5. 监控网络使用情况
  6. 在其他线程中解析Api响应数据
  7. 平滑滚动

因为我只想分享优化点,所以我不想附加详细代码或存储库。

触感

触摸响应度是用户由于输入而从设备获得反馈所花费的时间。 如果花费更长的时间,则意味着您的应用程序很笨拙。

要测量触摸响应时间,您可以测量从触发触摸事件到视图出现的时间。 然后,如何检测设备上的第一次触摸事件? 为此,制作一个名为MyApplication的自定义UIApplication来覆盖“ sendEvent:”。

  // 。H 
外部CFTimeInterval touchStartTime;
  // .m 
CFTimeInterval touchStartTime;
  @实现MyApplication 

-(void)sendEvent:(UIEvent *)event {
touchStartTime = CACurrentMediaTime();
  [super sendEvent:event]; 
}
  @结束 

要应用自定义UIApplication,请转到“ main.m”并将“ MyApplication”放入“ UIApplicationMain”方法中。

  #import“ AppDelegate.h” 
#import“ MyApplication.h”
  int main(int argc,char * argv []){ 
@autoreleasepool {
返回UIApplicationMain(argc,argv,@“ MyApplication”,NSStringFromClass([AppDelegate class]);
}

然后,选择要测量触摸响应时间的目标视图,并在显示该视图时将其与“ touchStartTime”进行比较。 如果它是视图控制器,那么“ viewWillAppear”将是最好的地方。

如果记录器花费的时间超出您的预期,请提醒视图控制器的生命周期,并检查“ loadView”和“ viewDidLoad”方法是否有效。 以我为例,某个视图控制器为时已晚,因为在主线程的“ viewDidLoad”中解析了一堆数据。

WebView中的触摸响应度

与UIWebView一起使用时,触摸响应时间需要300毫秒以上,这是响应Apple认为与用户交互的适当时间,但开发人员仍然可以减少此时间。 通过在Javascript级别捕获触摸事件并更改为自定义事件处理程序,可以消除此延迟的触摸。 这是一篇很棒的文章,介绍了如何覆盖它。

http://developer.telerik.com/featured/300-ms-click-delay-ios-8/

另一方面,您可以简单地使用WKWebView而不是UIWebView,默认的300ms触摸延迟就消失了。 听起来很完美,您可以将每个单独的Web视图都更改为wkWebView,但这存在一些问题。 它需要iOS 9或更高版本,不支持某些缓存,cookie设置问题等。您可以在此处查看问题。

http://docs.kioskproapp.com/article/840-wkwebview-supported-features-known-issues

应用启动时间

应用程序从后台启动到前台有两种方式:冷启动和暖启动。

当您的应用程序无法维持在内存区域时,就会发生冷启动,因此需要从头开始加载所有必需的数据。 请参阅WWDC视频片段“优化应用程序启动时间”可以帮助您了解在冷启动时间实际上发生了什么事情。

https://developer.apple.com/videos/play/wwdc2016/406/

老实说,实际上没有多少解决方案可以改善应用程序的冷启动时间。 但是,仍然可以通过在警告启动期间进行调整来使应用程序更快。 从“ main.m”到第一个视图控制器的“ viewWillAppear”调用检查代码。 通常,AppDelegate中的“ application:didFinishLaunchingWithOptions:”方法将成为主要目标,因为您请求主api调用,设置应用程序的视图体系结构并解析所有数据。

减少影像资源

应用程序的IPA文件由您自己的代码,库的代码和资源组成。 其中,在我的案例中也一样,使应用程序的应用程序尺寸更大的罪犯是图像资源。 使用后面的命令,您可以检查这些图像资源占用了多少文件大小。

 解压缩-lv YOUR_APP.ipa | 排序-k + 3nr | 头 

您可以通过删除冗余图像,更改图像格式或Xcode上的事件重新定向成员资格设置来减小资产大小。 就我而言,我将资产的目标设置为我的主应用程序,也将目标设置为小部件扩展,这导致IPA文件中Assets.car的重复。 因此,我简单地将扩展代码中使用的所有图像从主要资产移动到扩展资产,我的应用程序大小减少了15%。

监控网络使用情况

减少网络数据使用量也是优化的重点。 可以使用许多选项来减少网络使用量,但是在开始工作之前,最好了解如何测量当前网络状态。

iOS上的所有默认URL连接都通过NSURLProtocol传递,这意味着,一旦您创建自定义URLProtocol并将其注册到协议池中,就可以检测到所有URL连接和数据事务。 这是示例代码。

  // 。H 
@interface CustomURLProtocol:NSURLProtocol
@结束
  // .n 
@implementation CustomURLProtocol
  //需要重写一些必需的方法 
+(BOOL)canInitWithRequest:(NSURLRequest *)request {
如果(![[[NSURLProtocol propertyForKey:@“ RequestFlag” inRequest:request] boolValue]){
返回是;
}
 返回否; 
}
  -(void)startLoading { 
NSURLRequest * request = // ...
[NSURLProtocol setProperty:@YES forKey:@“ RequestFlag” inRequest:request];
  NSURLSession *会话= // ... 
[[session dataTaskWithRequest:request]简历];
}
  #pragma标记-NSURLSessionDelegate 
  -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { 

//接收数据
//在此处添加代码
  [[自我客户] URLProtocol:self didLoadData:data]; 
}
  -(void)URLSession:(NSURLSession *)会话任务:(NSURLSessionTask *)任务didCompleteWithError:(NSError *)error { 
  //收到所有数据 
//在此处添加代码
 如果(错误==无){ 
[[自我客户] URLProtocolDidFinishLoading:self];
}其他{
[[自我客户] URLProtocol:self didFailWithError:error];
}
}
  @结束 

这个示例代码还不够完善,但是仍然可以帮助您了解事情的进展。 使用NSURLSessionDelegate,您可以从头到尾衡量每个网络连接。

如果您的应用程序对网络请求使用库,例如​​AFNetworking,SDWebImage等,则在此自定义url协议类中不会检测到该网络连接; 这些库都有自己的url会话。 希望大多数网络库都通过通知中心提供其网络状态,您仍然可以捕获网络状态的每个阶段。

在其他线程中解析Api响应数据

通常应该在与主线程不同的线程中调用api请求。 许多著名的库还在它们自己的线程池上处理api网络连接。 但是,当api请求结束时,该过程又返回到主线程,通常,开发人员毫无疑问地在同一线程中进行了一堆解析数据。 检查您的api网络模块以及代码中解析响应数据的位置。

从服务器获取数据时,我遇到了很大的延迟问题。 api响应通常小于500kb,但是一旦意外增加到10MB以上,就需要2到3秒钟来解析所有数据并猜测是什么,我的应用程序在解析过程中被冻结。

平滑滚动

如果市场上几乎所有应用程序都至少包含一个表视图或集合视图,我不会感到惊讶。 在Apple提供的所有组件中,这两个组件可能是最常用的组件。 客户总是在应用程序中上下滚动。 如果滚动动作不够平滑,则会严重影响负面的用户体验。

改善平滑滚动的一种方法是预先预取数据和单元格。 如果单元格根据数据动态增长,则绘制单元格的大部分时间都用于计算单元格的高度。 即使Apple提供了“ estimatedRowHeight”选项,它也不会有太大帮助。

希望iOS 10的UICollectionView类可以通过预取和生命周期功能改进之类的底层更改保证更好的性能。 它支持“ UICollectionViewDataSourcePrefetching”协议,并包含两个实例函数。

  -(void)collectionView:(UICollectionView *)collectionView prefetchItemsAtIndexPaths:(NSArray  *)indexPaths //必需 
  -(void)collectionView:(UICollectionView *)collectionView cancelPrefetchingForItemsAtIndexPaths:(NSArray  *)indexPaths //可选 

对于tableView组件和低于iOS 10的代码,您可以像UICollectionView一样制作自定义预取模块,提前计算单元格的高度约5或更大。

合计

没有黑魔法也没有银弹可以立即提高应用程序的性能。 而且差异应用程序内部也具有差异逻辑。 我相信,时间和持续的努力只能挽救低质量的应用程序。