十年专注于品牌网站建设 十余年专注于网站建设_小程序开发_APP开发,低调、敢创新、有情怀!
南昌百恒网络微信公众号 扫一扫关注
小程序
tel-icon全国服务热线:400-680-9298,0791-88117053
扫一扫关注百恒网络微信公众号
扫一扫打开百恒网络微信小程序

百恒网络

南昌百恒网络

如何进行程序性能优化(三)

百恒网络 2017-05-20 4300

1.可重用对象的使用

在iOS的一些视图中,它们的内部包含了子视图,当父视图显示区域发生变化时(如用手滑动屏幕),原来在屏幕中的子视图就会滑出到屏幕之外,而原来在屏幕之外的子视图就有机会进入屏幕中。如图1所示,当屏幕向上滑动时,Cupertino单元格滑出屏幕之外,Sherman Oaks单元格滑入到屏幕中。

表视图中的可重用单元格

图1 表视图中的可重用单元格

这些操作会有什么问题吗?南昌网络公司小编告诉你如果每次新单元格进入到屏幕中都去实例化一个新的单元格,必然增加内存开销。采用可重用对象设计可以不去实例化新的单元格,而是先使用可重用单元格标识到视图中去找,如果找到则使用,没有则创建。

在iOS 6之后,可以使用可重用对象的父视图有表视图、集合视图(UICollectionView)和地图视图(MKMapView)。

1.1 表视图中的可重用对象

在iOS 6之后,表视图中有两种子视图采用可重用对象设计,它们是表视图单元格(UITableViewCell)和表视图节头节脚(UITableViewHeaderFooterView)。

(1)表视图单元格

表视图单元格的重用方法有两个:dequeueReusableCellWithIdentifier:方法和 dequeueReusableCellWithIdentifier:forIndexPath:方法。

通过dequeueReusableCellWithIdentifier:方法,可以用标识符从表视图中获得可重用单元格,模式代码如下:

通过dequeueReusableCellWithIdentifier:方法,可以用标识符从表视图中获得可重用单元格,模式代码

要在表视图数据源的tableView:cellForRowAtIndexPath:方法中使用可重用单元格设计,首先通过dequeueReusableCellWithIdentifier:方法从表视图中找,如果cell为空,则需要使用initWithStyle:reuseIdentifier:构造器创建。

dequeueReusableCellWithIdentifier:forIndexPath:方法是iOS 6之后提供的方法。与上一个方法相比,该方法的签名多了forIndexPath:部分。它可以通过指定单元格位置获得可重用单元格,不需要判断,模式代码如下:

dequeueReusableCellWithIdentifier:forIndexPath

这个方法的使用有一些限制,它只能应用于iOS故事板中,并且在故事板中设计表视图单元格后,指定表视图单元格为动态的,Identifier属性设置为cellIdentifier。图2设定了表视图单元格的属性。

设定表视图单元格的属性

图2 设定表视图单元格的属性

(2)UITableViewHeaderFooterView也是iOS 6之后新加的内容,节头和节脚也会反复出现,它也需要可重用设计。使用表视图的dequeueReusableHeaderFooterViewWithIdentifier:方法获得UITableViewHeaderFooterView对象后,如果没有可重用的UITableViewHeaderFooterView对象,则使用initWithReuseIdentifier:构造器创建。其模式代码如下:

UITableViewHeaderFooterView

需要在表视图委托协议UITableViewDelegate中的tableView:viewForHeaderInSection:方法中使用可重用对象设计。

1.2 集合视图中的可重用对象

集合视图在iOS 6之后才可以使用。它也有两种子视图采用可重用对象设计,它们是单元格视图和补充视图,这两个视图都继承自UICollectionReusableView,使用时需要自己编写相关代码。

(1)单元格视图

在集合视图中,我们可以使用UICollectionView的dequeueReusableCellWithReuseIdentifier:forIndexPath:方法获得可重用的单元格,模式代码如下:

使用UICollectionView的dequeueReusableCellWithReuseIdentifier:forIndexPath:方法获得可重用的单元格,模式代码

在上述代码中,collectionView:cellForItemAtIndexPath:方法是集合视图的数据源方法,其中Cell是我们自定义的继承自UICollectionReusableView的单元格类。使用dequeueReusableCellWithReuseIdentifier:时,需要使用故事板设计UI,并且需要将单元格的Identifier属性设置为Cell(如图3所示)。

设定集合视图单元格的属性

图3 设定集合视图单元格的属性

(2)补充视图

集合视图单元格可以使用UICollectionView的dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:方法获得可重用的补充视图,模式代码如下:

使用UICollectionView的dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:方法获得可重用的补充视图,模式代码

collectionView:viewForSupplementaryElementOfKind:atIndexPath:方法是集合视图的数据源方法,其中HeaderView是我们自定义的继承自UICollectionReusableView的补充视图类。使用dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:时,需要使用故事板设计UI,并将补充视图的Identifier属性设置为HeaderIdentifier,如图4所示。

设定补充视图的属性

图4 设定补充视图的属性

1.3 地图视图中的可重用对象

在开发地图应用时,也有一个可重用对MKPinAnnotationView,它是在地图上的一个标注。使用地图视图的

dequeueReusableAnnotationViewWithIdentifier:方法,可以获得MKPinAnnotationView对象。如果没有可重用的MKPinAnnotationView对象,则使用initWithAnnotation:reuseIdentifier:构造器创建。其模式代码如下:

dequeueReusableAnnotationViewWithIdentifier

initWithAnnotation:reuseIdentifier:构造器

这段处理代码是地图视图中常用的处理方式,请大家牢记。

2.并发处理与多核 CPU

并发处理能够同时处理多个任务。在CPU单核时代,可以使用多线程技术进行并发处理。现在,iOS设备的CPU已经进入多核时代,从iPhone 4S和iPad 2之后开始采用A5双核CPU设计。异步设计方法可以充分地发挥多核优势。GCD(Grand Central Dispatch)是一种异步方法,是专为多核CPU而设计的并发处理技术。

本节中,南昌网络公司小编就和大家一起来学习主线程阻塞问题以及GCD的相关内容。

2.1 主线程阻塞问题

主线程所做的事情应该是响应用户输入、事件处理、更新UI,而耗时的任务不要在主线程中处理。由于耗时任务使得主线程被阻塞了,不能响应用户的请求,这样应用的用户体验会很差。

下面我们先看一个例子。如图5所示,点击Load Image按钮,会从http://www.51work6.com/book/test2.jpg中加载图片。当我们点击Load Image按钮时,按钮会一直处于按下状态而不弹起,直到图片显示“完成”。这是因为主线程要进行耗时的处理(如进行网络通信、数据传输等任务),导致主线程不能响应用户的输入和请求,这就是我们要讨论的线程阻塞问题。

主线程阻塞案例

图5 主线程阻塞案例

下面我们看看代码部分。在BlockDemo工程中,ViewController中click:方法的代码如下:

ViewController中click:方法的代码

由于不能直接通过URL创建UIImage对象,因此先构建NSData对象,它是从URL请求回来的二进制数据对象,然后再用它来构建UIImage对象。最后,把UIImage对象赋值给UIImageView的image属性。

那么,如何解决主线程阻塞问题呢?那就是把这些执行比较耗时的阻塞线程的任务从主线程中移出到其他线程中处理。

2.2 选择 NSThread 还是 GCD

解决主线程阻塞问题时,我们可以使用多线程。NSThread是多线程类,但是麻烦的是我们需要管理线程,包括创建线程、线程间通信和销毁线程等。

GCD(Grand Central Dispatch)是基于C语句级别的API,它提供了C函数。GCD代码编写简单,还支持多核CPU处理。GCD是苹果重点推荐的并发技术,唯一的缺陷是它是基于C语言的API。

在GCD中,有一个重要的概念,那就是派发队列(dispatch queue)。派发队列是一个对象,它可以接受任务,并将任务以先到先执行的顺序来执行。派发队列可以是并发的或串行的。并发队列可以执行多任务,串行队列同一时间只执行单一任务。在GCD中,有3种类型的派发队列。

串行队列。串行队列通常用于同步访问一个特定的资源,每次只能执行一个任务。使用函数dispatch_queue_create,可以创建串行队列。

并发队列。也称为全局派发队列,可以并发地执行一个或多个任务。并发队列分为高、中、低3个优先级,中级为默认级别。可以调用dispatch_get_global_queue函数设定优先级来访问队列。dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)语句用于获得并发队列对象,其中DISPATCH_QUEUE_PRIORITY_DEFAULT是默认的优先级常量。

主队列。它在应用程序的主线程中,用于更新UI。其他的两个队列不能更新UI。使用dispatch_get_main_queue函数,可以获得主队列。

我们把BlockDemo工程修改为GCD实现,具体代码如下:

BlockDemo工程修改为GCD

在上述代码中,dispatch_async函数用于异步执行任务,但是它在串行队列中仍然是同步执行的。在更新UI时,如self.imageView.image = img语句,dispatch_async函数必须在主线程中执行。我们使用第①行代码在主队列中更新UI。

通过近几天的学习,我们了解了性能优化方法,其中包括内存优化、资源文件优化、延迟加载、持久化优化、使用可重用对象和并发访问等。这些内容都是非常重要的,希望对大家有所帮助。了解更多相关资讯,关注南昌网络公司--百恒网络官方网站。百恒网络是一家专业从事南昌网站建设、微信开发、APP开发、网络营销等服务的南昌网络公司,技术过硬,经验丰富。如有任何网站方面的问题,百恒网络随时欢迎大家来电咨询,我们专业为您解答!


400-680-9298,0791-88117053
扫一扫关注百恒网络微信公众号
扫一扫打开百恒网络小程序

欢迎您的光顾,我们将竭诚为您服务×

售前咨询 售前咨询
 
售前咨询 售前咨询
 
售前咨询 售前咨询
 
售前咨询 售前咨询
 
售前咨询 售前咨询
 
售后服务 售后服务
 
售后服务 售后服务
 
备案专线 备案专线
 
×