1.
如何让你的应用程序更加省电?
答:
(1)
如果程序用到定位,需要在定位完毕之后关闭定位,或者降低定位的频率,不停的定位会消耗电量。
(2)
如果用到了蓝牙,需要使用蓝牙时候开启蓝牙,蓝牙用完之后关闭蓝牙,蓝牙也很耗电。
(3)
优化算法,减少循环次数,大量循环会让
CPU
一直处于忙碌状态,特别费电。
(4)
不要使用网络轮询,使用推送。
(5)timer
的时间间隔不宜太短,满足需求即可。
(5)
不要频繁刷新页面,能刷新
1
行
cell
,不要
reloadData
。
(6)
切勿让屏幕长亮。
(7)
线程适量,不宜过多。
57.
简单描述你一下在开发的过程中,如何实现程序的性能优化?
答:我在开发的过程中会注意一下几点来优化程序性能:
1.
避免庞大的
XIB
2.
使用懒加载的方式延迟加载界面
3.
避免反复处理数据
4.
避免使用
NSDateFormatter
和
NSCalendar
。
5.
图片缓存的取舍
UIImage
加载图片方式一般有两种
:
A
:
imagedNamed
初始化
B
:
imageWithContentsOfFile
初始化
二者不同之处在于
,imageNamed
默认加载图片成功后会内存中缓存图片
,
这个方法用一个指定的名字在系统缓存中查找并返回一个图片对象
.
如果缓存中没有找到相应的图片对象
,
则从指定地方加载图片然后缓存对象,并返回这个图片对象
.
而
imageWithContentsOfFile
则仅只加载图片
,
不缓存
.
大量使用
imageNamed
方式会在不需要缓存的地方额外增加开销
CPU
的时间来做这件事
.
当应用程序需要加载一张比较大的图片并且使用一次性,那么其实是没有必要去缓存这个图片的,用
imageWithContentsOfFile
是最为经济的方式
,
这样不会因为
UIImage
元素较多情况下,
CPU
会被逐个分散在不必要缓存上浪费过多时间
.
使用场景需要编程时,应该根据实际应用场景加以区分,
UIImage
虽小,但使用元素较多问题会有所凸显
.
8
、
tableView
的重用机制?
查看
UITableView
头文件,会找到
NSMutableArray* visiableCells
,和
NSMutableDictnery*reusableTableCells
两个结构。
visiableCells
内保存当前显示的
cells
,
reusableTableCells
保存可重用的
cells
。
TableView
显示之初,
reusableTableCells
为空,那么
tableViewdequeueReusableCellWithIdentifier:CellIdentifier
返回
nil
。开始的
cell
都是通过
[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]
来创建,而且
cellForRowAtIndexPath
只是调用最大显示
cell
数的次数。
比如:有
100
条数据,
iPhone
一屏最多显示
10
个
cell
。程序最开始显示
TableView
的情况是:
1.
用
[[UITableViewCellalloc] initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:CellIdentifier]
创建
10
次
cell
,并给
cell
指定同样的重用标识
(
当然,可以为不同显示类型的
cell
指定不同的标识
)
。并且
10
个
cell
全部都加入到
visiableCells
数组,
reusableTableCells
为空。
2.
向下拖动
tableView
,当
cell1
完全移出屏幕,并且
cell11(
它也是
alloc
出来的,原因同上
)
完全显示出来的时候。
cell11
加入到
visiableCells
,
cell1
移出
visiableCells
,
cell1
加入到
reusableTableCells
。
3.
接着向下拖动
tableView
,因为
reusableTableCells
中已经有值,所以,当需要显示新的
cell
,
cellForRowAtIndexPath
再次被调用的时候,
tableViewdequeueReusableCellWithIdentifier:CellIdentifier
,返回
cell1
。
cell1
加入到
visiableCells
,
cell1
移出
reusableTableCells
;
cell2
移出
visiableCells
,
cell2
加入到
reusableTableCells
。之后再需要显示的
Cell
就可以正常重用了。
如何减小一个应用程序占用存储空间?
检查程序
去掉多余的
xib
。
iOS App Store
相关因素作为提交到
App Store
中
app
里的可执行文件是被加过密的。加密的副作用是可执行文件的压缩效果没有之前的好了。
Build Settings
编译选项,将
build setting
中的
Optimization Level
设置为
Fastest, Smallest [-Os];
将
build setting
中的
Strip Debug Symbols During Copy
设置为
YES(COPY_PHASE_STRIP = YES)
,这样可以减小编译出二进制文件的尺寸。
Target
针对较少的
CPUs
对程序指定的特定
CPU
类型做优化处理,以生成相对于的可执行文件。不同的硬件,将运行不同的可执行代码。虽然这样优化后的程序,只能针对某些设备运行,但是这大大减小可执行程序的大小。要想只设定特定类型的
CPUs
,可以修改
build setting
中的
Architectures
,将其从
Standard $(ARCHS_STANDARD)
修改为你希望支持的列表中对应的特定类型
CPU
。有效的
CPU
名称列在
Valid Architectures (VALID_ARCHS) build setting
中。请不要修改
Valid Architectures
设置项,最好由
Xcode
管理。尽量使用
8-bit
图片。使用
8-bit
的
PNG
图片,比
32-bit
的图片能减少
4
倍的压缩率。由于
8-bit
的图片支持最多
256
种不同的颜色,所以
8-bit
的图片一般只应该用于一小部分
的颜色图片。例如灰度图片最好使用
8-bit
如何提高一个应用程序的性能?
1、使用ARC减少内存失误,dealloc需要重写并对属性置nil。2、重用。3、尽量少使用透明或半透明。会产生额外的运算。4、少用运算获得圆角,不论view.maskToBounds还是layer.clipToBounds都会有很大资源开销,必须要用圆角的话不如图片本身就做成圆角。5、不要阻塞主线程。6、使用正确的容器类型。7、图片与imageView相同大小避免多余运算。8、使用懒加载。9、使用绘制。
如何优化内存?
(1). 用ARC管理内存
ARC(Automatic ReferenceCounting, 自动引用计数)和iOS5一起发布,它避免了最常见的也就是经常是由于我们忘记释放内存所造成的内存泄露。它自动为你管理retain和release的过程,除了帮你避免内存泄露,ARC还可以帮你提高性能,它能保证释放掉不再需要的对象的内存。
(2). 在正确的地方使用reuseIdentifier
一个开发中常见的错误就是没有给UITableViewCells, UICollectionViewCells,甚至是UITableViewHeaderFooterViews设置正确的reuseIdentifier。
(3).尽量把views设置为透明
如果你有透明的Views你应该设置它们的opaque属性为YES。
原因是这会使系统用一个最优的方式渲染这些views。如果设为YES,渲染系统就认为这个view是完全不透明的,这使得渲染系统优化一些渲染过程和提高性能。如果设置为NO,渲染系统正常地和其它内容组成这个View。默认值是YES。
(4).避免过于庞大的XIB
当你加载一个XIB的时候所有内容都被放在了内存里,包括任何图片。如果有一个不会即刻用到的view,你这就是在浪费宝贵的内存资源了。
(5).不要阻塞主线程
永远不要使主线程承担过多。因为UIKit在主线程上做所有工作,渲染,管理触摸反应,回应输入等都需要在它上面完成。
一直使用主线程的风险就是如果你的代码真的block了主线程,你的app会失去反应。
大部分阻碍主进程的情形是你的app在做一些牵涉到读写外部资源的I/O操作,比如存储或者网络。
(6). 在Image Views中调整图片大小
如果要在`UIImageView`中显示一个来自bundle的图片,你应保证图片的大小和UIImageView的大小相同。在运行中缩放图片是很耗费资源的,特别是`UIImageView`嵌套在`UIScrollView`中的情况下。
如果图片是从远端服务加载的你不能控制图片大小,比如在下载前调整到合适大小的话,你可以在下载完成后,最好是用background thread,缩放一次,然后在UIImageView中使用缩放后的图片。
(7). 选择正确的Collection
学会选择对业务场景最合适的类或者对象是写出能效高的代码的基础。当处理collections时这句话尤其正确。
一些常见collection的总结:
· Arrays: 有序的一组值。使用index来lookup很快,使用value lookup很慢,插入/删除很慢。
·Dictionaries: 存储键值对。用键来查找比较快。
· Sets: 无序的一组值。用值来查找很快,插入/删除很快。
(8). 打开gzip压缩
大量app依赖于远端资源和第三方API,你可能会开发一个需要从远端下载XML, JSON, HTML或者其它格式的app。
问题是我们的目标是移动设备,因此你就不能指望网络状况有多好。一个用户现在还在edge网络,下一分钟可能就切换到了3G。不论什么场景,你肯定不想让你的用户等太长时间。
减小文档的一个方式就是在服务端和你的app中打开gzip。这对于文字这种能有更高压缩率的数据来说会有更显著的效用。
好消息是,iOS已经在NSURLConnection中默认支持了gzip压缩,当然AFNetworking这些基于它的框架亦然。像Google App Engine这些云服务提供者也已经支持了压缩输出。
(9). 重用和延迟加载(lazy load) Views
更多的view意味着更多的渲染,也就是更多的CPU和内存消耗,对于那种嵌套了很多view在UIScrollView里边的app更是如此。
这里我们用到的技巧就是模仿`UITableView`和`UICollectionView`的操作:不要一次创建所有的subview,而是当需要时才创建,当它们完成了使命,把他们放进一个可重用的队列中。
这样的话你就只需要在滚动发生时创建你的views,避免了不划算的内存分配。
创建views的能效问题也适用于你app的其它方面。想象一下一个用户点击一个按钮的时候需要呈现一个view的场景。有两种实现方法:
1. 创建并隐藏这个view当这个screen加载的时候,当需要时显示它;
2. 当需要时才创建并展示。
每个方案都有其优缺点。用第一种方案的话因为你需要一开始就创建一个view并保持它直到不再使用,这就会更加消耗内存。然而这也会使你的app操作更敏感因为当用户点击按钮的时候它只需要改变一下这个view的可见性。
第二种方案则相反-消耗更少内存,但是会在点击按钮的时候比第一种稍显卡顿。
(10). Cache, Cache, 还是Cache!
一个极好的原则就是,缓存所需要的,也就是那些不大可能改变但是需要经常读取的东西。
我们能缓存些什么呢?一些选项是,远端服务器的响应,图片,甚至计算结果,比如UITableView的行高。
NSURLConnection默认会缓存资源在内存或者存储中根据它所加载的HTTP Headers。你甚至可以手动创建一个NSURLRequest然后使它只加载缓存的值。
(11).权衡渲染方法
在iOS中可以有很多方法做出漂亮的按钮。你可以用整幅的图片,可调大小的图片,uozhe可以用CALayer, CoreGraphics甚至OpenGL来画它们。
当然每个不同的解决方法都有不同的复杂程度和相应的性能。
简单来说,就是用事先渲染好的图片更快一些,因为如此一来iOS就免去了创建一个图片再画东西上去然后显示在屏幕上的程序。问题是你需要把所有你需要用到的图片放到app的bundle里面,这样就增加了体积–这就是使用可变大小的图片更好的地方了:你可以省去一些不必要的空间,也不需要再为不同的元素(比如按钮)来做不同的图。
然而,使用图片也意味着你失去了使用代码调整图片的机动性,你需要一遍又一遍不断地重做他们,这样就很浪费时间了,而且你如果要做一个动画效果,虽然每幅图只是一些细节的变化你就需要很多的图片造成bundle大小的不断增大。
总得来说,你需要权衡一下利弊,到底是要性能能还是要bundle保持合适的大小。
(12).处理内存警告
一旦系统内存过低,iOS会通知所有运行中app。如果你的app收到了内存警告,它就需要尽可能释放更多的内存。最佳方式是移除对缓存,图片object和其他一些可以重创建的objects的strong references.
幸运的是,UIKit提供了几种收集低内存警告的方法:
· 在app delegate中使用`applicationDidReceiveMemoryWarning:`的方法
· 在你的自定义UIViewController的子类(subclass)中覆盖`didReceiveMemoryWarning`
· 注册并接收UIApplicationDidReceiveMemoryWarningNotification的通知
一旦收到这类通知,你就需要释放任何不必要的内存使用。
例如,UIViewController的默认行为是移除一些不可见的view,它的一些子类则可以补充这个方法,删掉一些额外的数据结构。一个有图片缓存的app可以移除不在屏幕上显示的图片。
(13).重用大开销对象
一些objects的初始化很慢,比如NSDateFormatter和NSCalendar。然而,你又不可避免地需要使用它们,比如从JSON或者XML中解析数据。
想要避免使用这个对象的瓶颈你就需要重用他们,可以通过添加属性到你的class里或者创建静态变量来实现。
注意如果你要选择第二种方法,对象会在你的app运行时一直存在于内存中,和单例(singleton)很相似。
还需要注意的是,其实设置一个NSDateFormatter的速度差不多是和创建新的一样慢的!所以如果你的app需要经常进行日期格式处理的话,你会从这个方法中得到不小的性能提升。
(14). 减少使用Web特性
UIWebView很有用,用它来展示网页内容或者创建UIKit很难做到的动画效果是很简单的一件事。
但是你可能有注意到UIWebView并不像不像驱动Safari的那么快。这是由于以JIT compilation为特色的Webkit的Nitro Engine的限制。
所以想要更高的性能你就要调整下你的HTML了。第一件要做的事就是尽可能移除不必要的javascript,避免使用过大的框架。能只用原生js就更好了。
另外,尽可能异步加载例如用户行为统计script这种不影响页面表达的javascript。
最后,永远要注意你使用的图片,保证图片的符合你使用的大小。使用Sprite sheet提高加载速度和节约内存。
(15). 优化Table ViewTable view需要有很好的滚动性能,不然用户会在滚动过程中发现动画的瑕疵。为了保证table view平滑滚动,确保你采取了以下的措施:
· 正确使用`reuseIdentifier`来重用cells
· 尽量使所有的view opaque,包括cell自身
· 避免渐变,图片缩放,后台选人
· 缓存行高
· 如果cell内现实的内容来自web,使用异步加载,缓存请求结果
· 使用`shadowPath`来画阴影
· 减少subviews的数量
-
尽量不适用`cellForRowAtIndexPath:`,如果你需要用到它,只用一次然后缓
存结果
· 使用正确的数据结构来存储数据
· 使用`rowHeight`, `sectionFooterHeight`和 `sectionHeaderHeight`来设定固定
的高,不要请求delegate
(16). 使用Autorelease Pool `NSAutoreleasePool`负责释放block中的autoreleased objects。一般情况下它会自动被UIKit调用。但是有些状况下你也需要手动去创建它。假如你创建很多临时对象,你会发现内存一直在减少直到这些对象被release的时候。这是因为只有当UIKit用光了autorelease pool的时候memory才会被释放。好消息是你可以在你自己的@autoreleasepool里创建临时的对象来避免这个行为:
NSArray *urls = <# An array of file URLs #>;
for(NSURL *url in urls) {
@autoreleasepool {
NSError *error;
NSString *fileContents = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
/* Process the string, creating and autoreleasing more objects. */
}
}
这段代码在每次遍历后释放所有autorelease对象
(17). 选择是否缓存图片
常见的从bundle中加载图片的方式有两种,一个是用`imageNamed`,二是用`imageWithContentsOfFile`,第一种比较常见一点。既然有两种类似的方法来实现相同的目的,那么他们之间的差别是什么呢?`imageNamed`的优点是当加载时会缓存图片。`imageNamed`的文档中这么说:这个方法用一个指定的名字在系统缓存中查找并返回一个图片对象如果它存在的话。如果缓存中没有找到相应的图片,这个方法从指定的文档中加载然后缓存并返回这个对象。
相反的,`imageWithContentsOfFile`仅加载图片。如果你要加载一个大图片而且是一次性使用,那么就没必要缓存这个图片,用`imageWithContentsOfFile`足矣,这样不会浪费内存来缓存它。
然而,在图片反复重用的情况下`imageNamed`是一个好得多的选择。
如何加强 iOS 里的列表滚动时的顺畅感?
1、UITableViewCell里不要添加太多subview,最好只添加一个cellview。
2、UITableViewCell 上的子View的opaque属性设为YES。其实默认也是不透明。UITableViewCell尽量不要包含透明的子View。
3、在cellview里,重写drawRect函数绘制UITableViewCell的内容。
4、在绘制字符串时,尽可能使用drawAtPoint: withFont:,而不要使用更复杂的drawAtPoint:(CGPoint)point forWidth:(CGFloat)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode; 如果要绘制过长的字符串,建议自己先截断,然后使用drawAtPoint: withFont:方法绘制。
5、在绘制图片时,尽量使用drawAtPoint,而不要使用drawInRect。drawInRect如果在绘制过程中对图片进行放缩,会特别消耗CPU。
6、如果绘制cell过程中,需要下载cell中的图片,建议在绘制cell一段时间后再开启图片下载任务。譬如先画一个默认图片,然后在0.5S后开始下载本cell的图片。
7、即使下载cell 图片是在子线程中进行,在绘制cell过程中,也不能开启过多的子线程。最好只有一个下载图片的子线程在活动。否则也会影响UITableViewCell的绘制,因而影响了UITableViewCell的滑动速度。(建议结合使用NSOpeartion和NSOperationQueue来下载图片,如果想尽可能找的下载图片,可以把[self.queuesetMaxConcurrentOperationCount:4];)
8、最好自己写一个cache,用来缓存UITableView中的UITableViewCell,这样在整个UITableView的生命周期里,一个cell只需绘制一次,并且如果发生内存不足,也可以有效的释放掉缓存的cell。
9、不要将tableview的背景颜色设置成一个图片。这回严重影响UITableView的滑动速度。在限时免费搜索里,我曾经翻过一个错误:self.tableView_.backgroundColor = [UIColorcolorWithPatternImage:[UIImageimageNamed:@"background.png"]]; 通过这种方式设置UITableView的背景颜色会严重影响UTIableView的滑动流畅性。修改成self.tableView_.backgroundColor = [UIColor clearColor];之后,fps从43上升到60左右。滑动比较流畅。
10、 cell的行高不是固定值,需要计算,则要尽可能缓存行高值,避免重复计算行高。这里指的是UITableViewDelegate里的行高函数。
1、举出两个实际开发应用程序中可以省电的例子。
(1)如果程序用到定位,需要在定位完毕之后关闭定位,或者降低定位的频率,
不停的定位会消耗电量。
(2)如果用到了蓝牙,需要使用蓝牙时候开启蓝牙,蓝牙用完之后关闭蓝牙,蓝
牙也很耗电。
(3)优化算法,减少循环次数,大量循环会让CPU一直处于忙碌状态,特别费电。
(4)不要使用网络轮询,使用推送。
(5)timer的时间间隔不宜太短,满足需求即可。
(6)不要频繁刷新页面,能刷新1行cell,不要reloadData。
(7)切勿让屏幕长亮。
(8)线程适量,不宜过多
3、怎么解决缓存池满的问题(cell)
ios中不存在缓存池满的情况,因为通常我们ios中开发,对象都是在需要的时候才会创建,有种常用的说话叫做懒加载,还有在UITableView中一般只会创建刚开始出现在屏幕中的cell,之后都是从缓存池里取,不会在创建新对象。缓存池里最多也就一两个对象,缓存池满的这种情况一般在开发java中比较常见,java中一般把最近最少使用的对象先释放。
//清楚cell的缓存
NSArray *subviews = [[NSArray alloc] initWithArray:cell.contentView.subviews];
for (UIView *subview in subviews) {
[subview removeFromSuperview];
2.TableView是怎么优化的?tableView下拉加载数据的时候为什么会出现卡顿,如何解决?
(1)使用不透明视图
(2)不要重复创建不必要的table cell。
(3)减少视图的数目。
(4)不要做多余的绘制工作。
(5)预渲染图像。
(6)不要阻塞主线程。
4、正常使用应用时,按HOME键退出。稍后再次打开,界面出现卡顿现象,尝试分析一下可能原因。
这是由iOS系统管理决定的,但APP退出在后台后,只有10秒的持续运行时间,然后暂停。但该APP还在内存中,当出现内存警告,也就是别的APP要运行,而此时内存又不足的情况下,系统会回收停在后台APP所占用的内存。如果出现这种情况,那么你再次打开你的APP,就会重新启动。
不知道你是为什么要让APP在后台还要继续运行,如果非得这样,那可以使用多线程技术中的gcd,可以让APP退出后继续运行很长一段时间(大概10分钟)
iOS APP类型:
1. 保存现场。按下Home键10秒内直接杀死进程,并释放内存。
2. iOS支持的“多任务”。按下Home键转入多任务状态,保留在内存中,但只能系统允许的动作:比如GPS,比如VoIP,比如音乐等等。
3. 真正的桌面级别的多任务。只有Safari/Mail是,苹果嫡系大都都不是。这个级别的app在后台没有任何限制动作。
无限制动作的程序,一会在用户无察觉的情况下耗光电力,二会有安全上面的问题(那些在后台依旧默默发送你的个人消息程序)
顺便提一句,后两种占用内存的app,也会在任意时间从内存中被砍掉,取决于你是否动用了其它app而导致内存不足。
真正不会被砍掉的后台,只有苹果那个通知系统。
3.什么时候会用到懒加载?如果需要展示大量图片的时候还要一个个去加载么?
懒加载,又称为延迟加载。说的通俗一点,就是在开发中,当程序中需要利用的资源时。在程序启动的时候不加载资源,只有在运行当需要一些资源时,再去加载这些资源。
我们知道iOS设备的内存有限,如果在程序在启动后就一次性加载将来会用到的所有资源,那么就有可能会耗尽iOS设备的内存。这些资源例如大量数据,图片,音频等等
16.
工程中的图片存在哪里,如何保证刷新后内存不断增加问题,以及节约用户流量
工程中使用的图片可以自己创建个文件夹进行存放你需要用的图片
,
也可以在你工程中的
Images.xcassets
文件中存放你的图片
.
解决刷新内存不断增加的问题
,
需要把你创建的控件布局写成对应类的属性
,
在
ViewDidLoad
中初始化一次
.
不要在其他的类方法里创建控件
.
刷新节约用户流量的方法就是在一定时间段中判断当前的请求时间和上次刷新的时间并限定一个时间范围在某个范围内刷新不重新请求数据
.
1.UIWebView
如何管理内存泄露的问题
.
在你点击按钮跳转界面是不要再你的
button
点击时间中创建你的
UIWebView,
把
UIWebView
创建成一条属性在你的
ViewDidLoad
中去初始化
,
在你点击
button
时再去给你的
WebView
指定需要现实的网址
.
这样的操作可以让你的
WebView
不会在你点击
button
的时候无限制的被创建
.
这样就不会让你的内存无限制的增长
.