ios多少会内存优化级别禁用好吗内存

优化和调试IOS内存技巧_百度文库
您的浏览器Javascript被禁用,需开启后体验完整功能,
享专业文档下载特权
&赠共享文档下载特权
&100W篇文档免费专享
&每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
优化和调试IOS内存技巧
&&优化和调试IOS内存技巧方法
阅读已结束,下载本文需要
定制HR最喜欢的简历
下载文档到电脑,同时保存到云知识,更方便管理
加入VIP
还剩15页未读,
定制HR最喜欢的简历
你可能喜欢51CTO旗下网站
iOS 内存管理:内存优化
所谓的内存优化,在设计程序的过程中,我们要在保证程序运行效率的前提下,尽量压缩程序运行时所占用的内存。无论硬件设备的内存有多大,程序运行时占用内存越少越好。下面我将介绍在开发项目过程中,一些优化内存的方法。
作者:bool周来源:| 09:26
所谓的内存优化,在设计程序的过程中,我们要在保证程序运行效率的前提下,尽量压缩程序运行时所占用的内存。无论硬件设备的内存有多大,程序运行时占用内存越少越好。下面我将介绍在开发项目过程中,一些优化内存的方法。
1.关于UITableView
在项目开发中,UITableView 是用的比较多的一个视图控件。如果能够对 UITableView 的使用做好优化,程序的性能将提高很多。
(1)善于使用UITableViewCell的重用机制
重用机制:这种机制下系统默认有一个可变数组 NSMutableArray* visiableCells,用来保存当前显示的cell。一个可变字典 NSMutableDictnery* reusableTableCells ,用来保存可重复利用的cell。UITableView 只会创建一屏幕的cell,放在 visiableCells中。每当cell滑出屏幕,就会放到 reusableTableCells 中,当要显示某一个位置的cell时,先去 reusableTableCells 中取,如果有,直接取来用;如果没有,就会创建。这样极大减少了内存的开销。
在iOS 6之后,在UITableView和UICollectionView中除了可以复用cell,还可以复用各个Section的Header和Footer。可见Apple一直在不断优化。在项目开发中,我们需要给 UITableViewCells、 UICollectionViewCells、UITableViewHeaderFooterViews设置正确的 reuseIdentifier。当有多类cell需要复用是,我们可以根据 reuseIdentifier 区分。我们可以在Xcode中设置,如下图:
下面是一个简单的cell复用的示例:
-&(UITableViewCell&*)tableView:(UITableView&*)tableView&cellForRowAtIndexPath:(NSIndexPath&*)indexPath&{&&&&&static&NSString&*cellIdentifier&=&&&&&&UITableViewCell&*cell&=&&&&&&&&&&&cellIdentifier&=&@&你的xib文件视图中标注的reuseIdentifier&;&&&&&cell&=&[tableView&dequeueReusableCellWithIdentifier:cellIdentifier];&&&&//根据identifier复用cell&&&&&&&&&&//如果没有对应的cell,创建cell&&&&&if(!cell){&&&&&&&&&cell&=&[[UITableViewCell&alloc]&initWithStyle:UITableViewCellStyleDefault&reuseIdentifier:cellIdentifier];&&&&&}&&&&&&&&&&return&&}&
复用cell是一个很好的机制,但是使用不当也会出现问题,也就是所谓的复用重叠问题。看下面代码:
我本打算将偶数行的设置为蓝色,基数行为默认颜色,并将cell的内容设置为行数,加以区分。结果如图:
从上图可以看出,开始初始化的13~14个cell正常,但是当滑动tableview时,就出现了问题,有的基数行cell也变为了蓝色。这是因为,下面的cell基本都是复用的,当没有显示指定cell的属性时,它就会使用已经创建过的cell的属性,导致有的蓝色有的白色。解决办法就是像下面这样写:
切记:当对多种cell赋予属性时,一定不能写在 if (!cell){} 里面,避免复用出现问题。
(2)优化UITableViewCell高度计算
UITableView有两个很重要的回调方法:tableView:cellForRowAtIndexPath:和tableView:heightForRowAtIndexPath:。很多人认为,在初始化tableview时,会先调用前者进行创建,然后再调用后者进行布局和属性设置。然而并非如此。真实的情况是这样的:UITableView是继承自UIScrollView的,需要先确定它的contentSize及每个Cell的位置,然后才会把重用的Cell放置到对应的位置。所以事实上,UITableView的回调顺序是先多次调用 tableView:heightForRowAtIndexPath: 以确定contentSize及Cell的位置,然后才会调用 tableView:cellForRowAtIndexPath:,从而来显示在当前屏幕的Cell。
举个例子:如果现在要显示20个Cell,当前屏幕显示5个。那么刷新(reload)UITableView时,UITableView会先调用20次 tableView:heightForRowAtIndexPath: 方法,然后调用5次tableView:cellForRowAtIndexPath:方法;滚动屏幕时,每当Cell滚入屏幕,都会调用一次tableView:heightForRowAtIndexPath:、tableView:cellForRowAtIndexPath:方法。
所以,对于UITableViewCell的高度计算的优化,就是对这两个函数的处理。至于如何优化@我就叫Sunny怎么了写了一篇很好的文章去介绍。我就不多说了。
(3) 懒加载(延迟加载)
懒加载并不是减少了程序内存消耗,而是将加载对象的时间推迟,在使用到对象的时候在对其进行初始化。例如一个UITableView一共有20行,但是屏幕只显示5行数组。那么在初始化tableview的时候,可以只先加载5行数据,另外15行等到显示的时候再去加载。这样可以减少初始化tableview时所需要的内存。(这样说有点牵强,因为实时加载会影响tableview的流畅度,但是大体就是这个意思 &&)
2.关于图片的处理
图片在内存中会占很大开销,如果适当的处理图片,会减少很多内存的消耗。
(1)缓存图片
常见的从bundle中加载图片的方式有两种,一个是用imageNamed,二是用imageWithContentsOfFile,第一种比较常见一点。
imageNamed的优点是当加载时会缓存图片。imageNamed的文档中这么说:
这个方法用一个指定的名字在系统缓存中查找并返回一个图片对象如果它存在的话。如果缓存中没有找到相应的图片,这个方法从指定的文档中加载然后缓存并返回这个对象。
也就是说,imageNamed方法加载的图片,会对图片进行缓存。而 imageWithContentsOfFile 方法不会。
所以,如果要加载的图片比较小,而且会反复使用,这种情况选择用 imageN如果要加载一个大图片,而且是一次性使用,那就使用 imageWithContentsOfFile,没必要浪费内存去缓存它。
代码示例:
(2)调整图片大小
我们经常从网络获取图片或者从本地bundle获取图片,然后加载到 UIImageView 中。在加载图片时,应尽量保证图片大小和 UIImageView 大小相同。因为在运行中缩放图片很耗费资源,如果 UIImageView 嵌套在 UIScrollView 或者 UITableView中,会更耗费资源。
对于从本地bundle中加载的图片,我们可以事先件图片处理好。对于从网络下载的图片,在下载完成后,我们需要对图片进行缩放,然后再加载。
(3)代码渲染 or 直接获取
前面已经说过,用代码去渲染一张图片会使图片占用内存翻倍。但是用代码去绘制图片,能够很好的去控制图片,并且能够做出很多漂亮的效果,前提是牺牲一部分内存;那如果所有图片都从bundle中加载呢?那会使bundle的体积增大,同时不能够用代码去灵活处理图片的效果。
所以,在开发过程中,是代码渲染图片,还是从bundle获取图片,需要做一个权衡。
3.数据处理
在项目开发中,我们会使用到各种格式的数据,例如 JSON、XML 等。还有各种各样的数据结构,例如数组、链表、字典、集合等。使用正确的数据格式和使用正确的数据结构,会减少我们的资源消耗。
(1)选择正确的数据格式
App与网络进行交互时,常常采用 JSON 或者 XML 类型的数据格式。
JSON 是一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性。解析 JSON 会比 XML更快,但是 JSON 传输的数据比较小。
XML 是一种重量级的数据交换格式,适用于很大的数据传输。当数据量较大时,使用 XML 数据格式,会极大减少内存消耗,增加性能。
另外,尽量避免数据多次转化。例如tableview中需要以数组的形势去赋值。那么服务器尽量返回数组类型。如果返回 JSON 类型,在去转换为 NSArray 类型,也会增加开销。
(2)选择正确的数据结构
不同的数据结构,处理数据的速度是不同的。
数组 NSArray NSMutableArray:有序的一组值。使用索引来查询很快,使用值查找很慢, 插入/删除很慢。
字典 NSDictionary NSMutableDictionary:存储键值对。用键来查找比较快。
集合 NSSet NSMutableSet:无序的一组值。用值来查找很快,插入/删除很快。
4.View的处理
(1)避免使用过于复杂的xib
在目前很多项目开发中,还经常用到 xib。当加载一个 xib 时,所有的内容都会放到内存里,包括任何图片。如果 xib 文件过于庞大,会占用很多内存。xib 与 storyboard 不同,xib即使暂时用不到,view也会存在于内存里;storyboard 仅在需要时实例化一个view controller。
而且设置view属性时,尽可能的把 opaque 属性设置为YES(不透明)。这样会提高渲染系统优化一些渲染过程和提高性能。
(2)正确设置View的背景
设置UIView的背景图片主要有两种方式:
使用 UIColor的 colorWithPatternImage 来设置背景色;
给 UIView 添加 UIImageView 子视图。
第一种方式,适合使用小图平铺创建背景,能更快渲染也不会会费很多内存。例如使用一个10x10的像素大小重复背景。
第二种方式,适合于使用大图,即整张图片来设置背景。如果使用 colorWithPatternImage 会消耗太多内存从而收到内存警告导致应用程序突然崩溃。而使用 UIImageView 会节约不少内存。
(3)设定Shadow Path
如果用下面代码给 view.layer 添加一个shadow:
这会使Core Animation 不得不在后台得出图形并加好阴影之后再去渲染,这会开销很大。
如果使用shadowPath则会避免这种问题:
5.合理使用Autorelease Pool
NSAutoreleasePool负责释放block中的autoreleased objects。一般情况下它会自动被UIKit调用。但是有些状况下也需要手动去创建它。
假如创建很多临时对象,你会发现内存一直在减少直到这些对象被release的时候。这是因为只有当UIKit用光了autorelease pool的时候memory才会被释放。
但是如果自己定义 @autoreleasepool ,在里面创建临时对象,可以避免这个问题:
6.正确处理缓存
缓存可以分为内存缓存和磁盘缓存。在项目开发过程中,我们经常会对一些图片、声音、数据进行缓存。合理利用缓存机制,会大大提高程序的性能,提高APP的流畅性。例如被广为使用的 SDWebImage,它使用的缓存机制是这样的:
(1)先根据查看内存缓存,如果有直接获取。
(2)如果内存没有,从磁盘缓存获取。
(3)如果磁盘缓存也没有,直接通过URL从网络下载。
当然这只是一个简单的描述,更加详细请看@南峰子_老驴的一篇SDWebImage实现分析。
合理处理缓存,能够提高程序的性能,不用每次都从网络获取数据。但是也不能什么都存入缓存,这会消耗很多内存和磁盘空间。所以应合理使用缓存机制。
以上,是我对于内存优化的一些理解。在写这篇文章过程中,参考了很多大牛的文章。对于一名在校应届本科生来说,我对于oc的理解还很浅薄,如果有错误或者有需要添加的地方,希望大家能够指出。我会加以改正并学习。
【编辑推荐】【责任编辑: TEL:(010)】
大家都在看猜你喜欢
热点热点热点热点头条
24H热文一周话题本月最赞
讲师:138786人学习过
讲师:9970人学习过
讲师:26人学习过
精选博文论坛热帖下载排行
Java是当前最流行的程序设计语言之一。本书以Java最新版本Java SE5为基础,涵盖了Java SE5最新特性,由浅入深地介绍了Java SE5的主要内容。...
订阅51CTO邮刊ios9.3正式版卡不卡 ios9.3正式版占多少内存_西西软件资讯
西西软件园多重安全检测下载网站、值得信赖的软件下载站!
→ ios9.3正式版卡不卡 ios9.3正式版占多少内存
v1.0.1苹果版
类型:休闲益智大小:0KB语言:中文 评分:10.0
今天的苹果春季发布会公布了ios9.3系统,很多用户都在犹豫要不要升级,很担心ios9.3更新了之后会不会卡,内存占用的多不多,下面西西就为大家详细介绍。ios9.3正式版卡不卡 ios9.3正式版占多少内存苹果官方已经于日前发布了最新的iOS9.3版系统,此次更新主要针对系统漏洞进行了修复,并且对部分功能进行升级。苹果官方已经发布了最新的iOS9.3 beta版系统,此次更新主要针对系统漏洞进行了修复,并且对部分功能进行升级,同时也将苹果Safari浏览器和第三方应用兼容性进行了再次升级。升级内容主要包括备忘录、健康应用、新闻、应用图标快捷操作、CarPlay、教育和Apple Watch等多个方面。那么,iOS9.3 beta值不值得升级呢?日前,网友 zjghfxwj 针对苹果此次发布的系统更新发表了自己的看法,如果P友们还在犹豫是否应该升级的话,不妨参考一下以下内容:1、流畅度对于大部分P友来说,还在犹豫是否应该更新 iOS9.3的主要原因在于担心升级之后的 iPhone 手机会变得很卡。不少已经升级到新版本的网友表示,iPhone 6S 升级新系统之后变得更流畅了,最主要的体验就是在下拉搜索第三方输入法的时候一点都不卡顿。2、耗电情况现如今,续航时间短已经成为了智能手机的一大缺点,iPhone 也不例外。因此,耗电情况成为了 iPhone 要不要升级到 iOS9.3 beta 的一个主要因素。不少网友表示,iPhone 6s 安装 iOS9.3 beta 之后,半个小时的音乐播放时间(在 WiFi 环境下)就耗掉了设备 10% 的电量。还有一些人表示,他们在蜂窝网络环境下只是浏览网页设备就会很快发烫,同时电量的消耗也比升级 iOS9.3 beta 之前更快了。3、占用内存升级 iOS9.3 需要 1.7GB 存储空间,相比较之前的版本,此次更新占用的内存要更大一些。所以在更新之前,P友们最好准备好充足的内存,避免出现更新失败情况。该网友表示,内存不够的网友可以清理一下手机里不常用的软件。如果升级新系统之后想要降级,最好在苹果关闭旧版本的验证之前,否则会给自己带来困扰。4、新增功能iOS9.3新增的夜间模式还是获得很多用户的好评。因为它允许 iPhone 用户调整屏幕的亮度。网友 zjghfxwj 最后给出的建议是,目前 iPhone 手机出现卡顿、掉帧等较为严重的问题的用户可以考虑升级到 iOS9.3,而如果对耗电非常介意的话,则暂时不建议升级。新了之前的曝光的问题,比如1970日期、Error53等错误,还增加了不少新功能:1、Night Shift简单来说,开启这个功能后,能够对屏幕色温进行调节,降低屏幕蓝光,从而起到保护视力的功效。2、3D Touch更多的快捷操作为了让3D Touch使用起来更便捷,苹果增加不少快捷操作,比如直接在App Store图标上,通过长按的方式购买或更新所有软件,长按设置图标,可快捷设定蓝牙、WiFi、电池模式或更换壁纸等等。3、配对多个Apple WatchiPhone升级只最新系统外,WatchOS升级到2.2,这样iPhone就可以与多个Apple Watch连接了。4、全新的CarPlay全新的CarPlay中,用户可以直接使用其中的地图“附近”查找功能,来定位周边的加油站、餐厅、咖啡厅或是停车场等兴趣点,同时用户还可以在CarPlay上的Apple Music,选择个性化的艺术家或专辑歌单。5、健康App优化用户进入新的健康应用后,通过侧滑彩蛋能找到能够兼容体重、锻炼或是睡眠数据的应用,同时你也可以与其他应用共享这些数据。
(69) 西西专区为各位喜欢僵尸榨汁机的玩家们带来了,,僵尸榨汁机安卓版下载僵尸榨汁机破解版下载僵尸榨汁机存档下载僵尸榨汁机电脑版下载僵尸榨汁机版下载僵尸榨汁机刷钻石修改器下载。喜欢的可以来西西专区下载体验,,僵尸榨汁机游戏简介僵尸榨汁机是一款非常有创新思维的经营类休闲游戏,在这个游戏中,制作者就大胆的采用了多种元素混合的游戏方式,游戏一开始你以为是一个跑酷游戏,画风突变又成了经营类游戏。僵尸榨汁机讲述了外星人...
06-06 / 73.9M
推荐理由:SteppyPants僵尸漫步ipad版是一款幽默搞笑玩法的休闲游戏,贱贱走路玩法看似简单,却可能成为你屡屡失败却又
04-20 / 0KB
推荐理由:僵尸猎人亡灵之死ios版是一款全新的动作射击类游戏,游戏以僵尸为题材,玩法类似于合金弹头,游戏内部的元素
04-19 / 54.1M
推荐理由:僵尸淘金记ios版是一款全新的休闲益智类游戏,游戏以僵尸为题材,玩家将驾驶一台自带机枪的小车,射击并碾压
04-12 / 106.5M
推荐理由:微商快手一键清理僵尸粉苹果版是一款专业的手机微信营销应用,其主要的功能就是可以一键清除僵尸粉,让你的
03-22 / 38.7M
推荐理由:僵尸家园VR这款游戏是非常有趣的体感射击类的手游,在这里你可以操作一名像素方块人来消灭各种方块像素僵尸
03-13 / 97.9M
推荐理由:植物大战僵尸英雄存档说明:游戏已得到破解存档,存档中金币为个、宝石为个,并且语言为中
03-2203-2203-2203-2203-2203-2203-2203-2203-2203-22
阅读本文后您有什么感想? 已有23人给出评价!
名称大小下载1.用ARC管理内存
ARC(Automatic ReferenceCounting, 自动引用计数)和iOS5一起发布,它避免了最常见的也就是经常是由于我们忘记释放内存所造成的内存泄露。它自动为你管理retain和release的过程,所以你就不必去手动干预了。忘掉代码段结尾的release简直像记得吃饭一样简单。而ARC会自动在底层为你做这些工作。除了帮你避免内存泄露,ARC还可以帮你提高性能,它能保证释放掉不再需要的对象的内存。
2.在正确的地方使用 reuseIdentifier
一个开发中常见的错误就是没有给UITableViewCells, UICollectionViewCells,甚至是UITableViewHeaderFooterViews设置正确的reuseIdentifier。
为了性能最优化,table view用tableView:cellForRowAtIndexPath:为rows分配cells的时候,它的数据应该重用自UITableViewCell。一个table view维持一个队列的数据可重用的UITableViewCell对象。
不使用reuseIdentifier的话,每显示一行table view就不得不设置全新的cell。这对性能的影响可是相当大的,尤其会使app的滚动体验大打折扣。
自iOS6起,除了UICollectionView的cells和补充views,你也应该在header和footer views中使用reuseIdentifiers。
想要使用reuseIdentifiers的话,在一个table view中添加一个新的cell时在data source object中添加这个方法:
staticNSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
这个方法把那些已经存在的cell从队列中排除,或者在必要时使用先前注册的nib或者class创造新的cell。如果没有可重用的cell,你也没有注册一个class或者nib的话,这个方法返回nil。
3.尽量把views设置为透明
如果你有透明的Views你应该设置它们的opaque属性为YES。
原因是这会使系统用一个最优的方式渲染这些views。这个简单的属性在IB或者代码里都可以设定。
Apple的文档对于为图片设置透明属性的描述是:
(opaque)这个属性给渲染系统提供了一个如何处理这个view的提示。如果设为YES,渲染系统就认为这个view是完全不透明的,这使得渲染系统优化一些渲染过程和提高性能。如果设置为NO,渲染系统正常地和其它内容组成这个View。默认值是YES。
在相对比较静止的画面中,设置这个属性不会有太大影响。然而当这个view嵌在scroll view里边,或者是一个复杂动画的一部分,不设置这个属性的话会在很大程度上影响app的性能。
你可以在模拟器中用Debug\Color Blended Layers选项来发现哪些view没有被设置为opaque。目标就是,能设为opaque的就全设为opaque!
4.避免过于庞大的XIB
iOS5中加入的Storyboards(分镜)正在快速取代XIB。然而XIB在一些场景中仍然很有用。比如你的app需要适应iOS5之前的设备,或者你有一个自定义的可重用的view,你就不可避免地要用到他们。
如果你不得不XIB的话,使他们尽量简单。尝试为每个Controller配置一个单独的XIB,尽可能把一个View Controller的view层次结构分散到单独的XIB中去。
需要注意的是,当你加载一个XIB的时候所有内容都被放在了内存里,包括任何图片。如果有一个不会即刻用到的view,你这就是在浪费宝贵的内存资源了。Storyboards就是另一码事儿了,storyboard仅在需要时实例化一个view controller.
当家在XIB是,所有图片都被cache,如果你在做OS X开发的话,声音文件也是。Apple在相关文档中的记述是:
当你加载一个引用了图片或者声音资源的nib时,nib加载代码会把图片和声音文件写进内存。在OS X中,图片和声音资源被缓存在named cache中以便将来用到时获取。在iOS中,仅图片资源会被存进named caches。取决于你所在的平台,使用NSImage 或UIImage的imageNamed:方法来获取图片资源。
5.不要阻塞主线程
永远不要使主线程承担过多。因为UIKit在主线程上做所有工作,渲染,管理触摸反应,回应输入等都需要在它上面完成。
一直使用主线程的风险就是如果你的代码真的block了主线程,你的app会失去反应。
大部分阻碍主进程的情形是你的app在做一些牵涉到读写外部资源的I/O操作,比如存储或者网络。
你可以使用NSURLConnection异步地做网络操作:
+(void)sendAsynchronousRequest:(NSURLRequest *)request queue:(NSOperationQueue*)queue completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))handler
或者使用像AFNetworking这样的框架来异步地做这些操作。
如果你需要做其它类型的需要耗费巨大资源的操作(比如时间敏感的计算或者存储读写)那就用 Grand Central Dispatch,或者NSOperation和 NSOperationQueues.
下面代码是使用GCD的模板
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
发现代码中有一个嵌套的dispatch_async吗?这是因为任何UIKit相关的代码需要在主线程上进行。
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然后使它只加载缓存的值。
下面是一个可用的代码段,你可以可以用它去为一个基本不会改变的图片创建一个NSURLRequest并缓存它:
+(NSMutableURLRequest *)imageRequestWithURL:(NSURL *)url {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.cachePolicy = NSURLRequestReturnCacheDataElseL
request.HTTPShouldHandleCookies = NO;
request.HTTPShouldUsePipelining = YES;
[request addValue:@"image/*"forHTTPHeaderField:@"Accept"];
注意你可以通过 NSURLConnection 获取一个URL request, AFNetworking也一样的。这样你就不必为采用这条tip而改变所有的networking代码了。
如果你需要缓存其它不是HTTP Request的东西,你可以用NSCache。
NSCache和NSDictionary类似,不同的是系统回收内存的时候它会自动删掉它的内容。
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可以移除不在屏幕上显示的图片。
这样对内存警报的处理是很必要的,若不重视,你的app就可能被系统杀掉。
然而,当你一定要确认你所选择的object是可以被重现创建的来释放内存。一定要在开发中用模拟器中的内存提醒模拟去测试一下。
13.重用大开销对象
一些objects的初始化很慢,比如NSDateFormatter和NSCalendar。然而,你又不可避免地需要使用它们,比如从JSON或者XML中解析数据。
想要避免使用这个对象的瓶颈你就需要重用他们,可以通过添加属性到你的class里或者创建静态变量来实现。
注意如果你要选择第二种方法,对象会在你的app运行时一直存在于内存中,和单例(singleton)很相似。
下面的代码说明了使用一个属性来延迟加载一个date formatter. 第一次调用时它会创建一个新的实例,以后的调用则将返回已经创建的实例:
@property (nonatomic, strong) NSDateFormatter *
- (NSDateFormatter *)formatter {
if(! _formatter) {
_formatter = [[NSDateFormatter alloc] init];
_formatter.dateFormat = @"EEE MMM dd HH:mm:ss
还需要注意的是,其实设置一个NSDateFormatter的速度差不多是和创建新的一样慢的!所以如果你的app需要经常进行日期格式处理的话,你会从这个方法中得到不小的性能提升。
14.使用Sprite Sheets
Sprite sheet可以让渲染速度加快,甚至比标准的屏幕渲染方法节省内存。
15.避免反复处理数据
许多应用需要从服务器加载功能所需的常为JSON或者XML格式的数据。在服务器端和客户端使用相同的数据结构很重要。在内存中操作数据使它们满足你的数据结构是开销很大的。
比如你需要数据来展示一个table view,最好直接从服务器取array结构的数据以避免额外的中间数据结构改变。
类似的,如果需要从特定key中取数据,那么就使用键值对的dictionary。
16.选择正确的数据格式
从app和网络服务间传输数据有很多方案,最常见的就是JSON和XML。你需要选择对你的app来说最合适的一个。
解析JSON会比XML更快一些,JSON也通常更小更便于传输。从iOS5起有了官方内建的JSON deserialization就更加方便使用了。
但是XML也有XML的好处,比如使用SAX来解析XML就像解析本地文件一样,你不需像解析json一样等到整个文档下载完成才开始解析。当你处理很大的数据的时候就会极大地减低内存消耗和增加性能。
17.正确设定背景图片
在View里放背景图片就像很多其它iOS编程一样有很多方法:
使用UIColor的 colorWithPatternImage来设置背景色;
在view中添加一个UIImageView作为一个子View。
如果你使用全画幅的背景图,你就必须使用UIImageView因为UIColor的colorWithPatternImage是用来创建小的重复的图片作为背景的。这种情形下使用UIImageView可以节约不少的内存:
// You could also achieve the same result in Interface Builder
UIImageView *backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"background"]];
[self.view addSubview:backgroundView];
如果你用小图平铺来创建背景,你就需要用UIColor的colorWithPatternImage来做了,它会更快地渲染也不会花费很多内存:
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"background"]];
18.减少使用Web特性
UIWebView很有用,用它来展示网页内容或者创建UIKit很难做到的动画效果是很简单的一件事。
但是你可能有注意到UIWebView并不像驱动Safari的那么快。这是由于以JIT compilation为特色的Webkit的Nitro Engine的限制。
所以想要更高的性能你就要调整下你的HTML了。第一件要做的事就是尽可能移除不必要的javascript,避免使用过大的框架。能只用原生js就更好了。
另外,尽可能异步加载例如用户行为统计script这种不影响页面表达的javascript。
最后,永远要注意你使用的图片,保证图片的符合你使用的大小。使用Sprite sheet提高加载速度和节约内存。
19.设定Shadow Path
如何在一个View或者一个layer上加一个shadow呢,QuartzCore框架是很多开发者的选择:
// Somewhere later ...
UIView *view = [[UIView alloc] init];
// Setup the shadow ...
view.layer.shadowOffset = CGSizeMake(-1.0f, 1.0f);
view.layer.shadowRadius = 5.0f;
view.layer.shadowOpacity = 0.6;
看起来很简单,对吧。可是,坏消息是使用这个方法也有它的问题… Core Animation不得不先在后台得出你的图形并加好阴影然后才渲染,这开销是很大的。
使用shadowPath的话就避免了这个问题:
view.layer.shadowPath = [[UIBezierPath bezierPathWithRect:view.bounds] CGPath]
使用shadow path的话iOS就不必每次都计算如何渲染,它使用一个预先计算好的路径。但问题是自己计算path的话可能在某些View中比较困难,且每当view的frame变化的时候你都需要去update shadow path.
20.优化Table View
Table view需要有很好的滚动性能,不然用户会在滚动过程中发现动画的瑕疵。
为了保证table view平滑滚动,确保你采取了以下的措施:
· 正确使用reuseIdentifier来重用cells
· 尽量使所有的view opaque,包括cell自身
· 避免渐变,图片缩放,后台选人
· 缓存行高
· 如果cell内现实的内容来自web,使用异步加载,缓存请求结果
· 使用shadowPath来画阴影
· 减少subviews的数量
· 尽量不适用cellForRowAtIndexPath:,如果你需要用到它,只用一次然后缓存结果
· 使用正确的数据结构来存储数据
· 使用rowHeight, sectionFooterHeight和 sectionHeaderHeight来设定固定的高,不要请求delegate
21.选择正确的数据存储选项
当存储大块数据时你会怎么做?
你有很多选择,比如:
· 使用NSUerDefaults
· 使用XML, JSON, 或者 plist
· 使用NSCoding存档
· 使用类似SQLite的本地SQL数据库
· 使用 Core Data
NSUserDefaults的问题是什么?虽然它很nice也很便捷,但是它只适用于小数据,比如一些简单的布尔型的设置选项,再大点你就要考虑其它方式了
XML这种结构化档案呢?总体来说,你需要读取整个文件到内存里去解析,这样是很不经济的。使用SAX又是一个很麻烦的事情。
NSCoding?不幸的是,它也需要读写文件,所以也有以上问题。
在这种应用场景下,使用SQLite 或者 Core Data比较好。使用这些技术你用特定的查询语句就能只加载你需要的对象。
在性能层面来讲,SQLite和Core Data是很相似的。他们的不同在于具体使用方法。Core Data代表一个对象的graph model,但SQLite就是一个DBMS。Apple在一般情况下建议使用Core Data,但是如果你有理由不使用它,那么就去使用更加底层的SQLite吧。
如果你使用SQLite,你可以用FMDB()这个库来简化SQLite的操作,这样你就不用花很多经历了解SQLite的C API了。
23.使用Autorelease Pool
NSAutoreleasePool负责释放block中的autoreleased objects。一般情况下它会自动被UIKit调用。但是有些状况下你也需要手动去创建它。
假如你创建很多临时对象,你会发现内存一直在减少直到这些对象被release的时候。这是因为只有当UIKit用光了autorelease pool的时候memory才会被释放。好消息是你可以在你自己的@autoreleasepool里创建临时的对象来避免这个行为:
NSArray *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对象
24.选择是否缓存图片
常见的从bundle中加载图片的方式有两种,一个是用imageNamed,二是用imageWithContentsOfFile,第一种比较常见一点。
既然有两种类似的方法来实现相同的目的,那么他们之间的差别是什么呢?
imageNamed的优点是当加载时会缓存图片。imageNamed的文档中这么说:这个方法用一个指定的名字在系统缓存中查找并返回一个图片对象如果它存在的话。如果缓存中没有找到相应的图片,这个方法从指定的文档中加载然后缓存并返回这个对象。
相反的,imageWithContentsOfFile仅加载图片。
下面的代码说明了这两种方法的用法:
UIImage *img = [UIImage imageNamed:@"myImage"];
UIImage *img = [UIImage imageWithContentsOfFile:@"myImage"];
那么我们应该如何选择呢?
如果你要加载一个大图片而且是一次性使用,那么就没必要缓存这个图片,用imageWithContentsOfFile足矣,这样不会浪费内存来缓存它。
然而,在图片反复重用的情况下imageNamed是一个好得多的选择。
25.避免日期格式转换
如果你要用NSDateFormatter来处理很多日期格式,应该小心以待。就像先前提到的,任何时候重用NSDateFormatters都是一个好的实践。
然而,如果你需要更多速度,那么直接用C是一个好的方案。Sam Soffes有一个不错的帖子()里面有一些可以用来解析ISO-8601日期字符串的代码,简单重写一下就可以拿来用了。
嗯,直接用C来搞,看起来不错了,但是你相信吗,我们还有更好的方案!
如果你可以控制你所处理的日期格式,尽量选择Unix时间戳。你可以方便地从时间戳转换到NSDate:
-(NSDate*)dateFromUnixTimestamp:(NSTimeInterval)timestamp {
return[NSDate dateWithTimeIntervalSince1970:timestamp];
这样会比用C来解析日期字符串还快!需要注意的是,许多web API会以微秒的形式返回时间戳,因为这种格式在javascript中更方便使用。记住用dateFromUnixTimestamp之前除以1000就好了。
参考链接:
iOS内存优化--大文件如何处理,内存映射
iOS开发经常使用到大文件,如大数据库,高清图片,视频资源,如果将这些数据缓存在内存中,会影响到内存性能。
笔者从内存映射入手,给大家展示下大文件的处理,1、在cache目录下,放一个视频文...
深入剖析 iOS 性能优化
问题种类时间复杂度在集合里数据量小的情况下时间复杂度对于性能的影响看起来微乎其微。但如果某个开发的功能是一个公共功能,无法预料调用者传入数据的量时,这个复杂度的优化显得非常重要了。上图列出了各种情况的...
iOS 浅谈app降低内存
device: (crash amount/total amount/percentage of total)
iPad1: 127MB/256MB/49%
iPad2: 275MB/512MB/...
http://www.cocoachina.com/ios/46.html
iOS开发者如何提高自己的水平?
不知道你有没有参与或是旁观过iO...
iOS开发中,必然会使用到显示图片.然而在你的APP中使用大量图片以后,检查内存时你会发现,哇!!!内
存已经超过200M甚至更多(模拟器中内存上不封顶).这时iPhone4很容易造成程序闪退,如果...
栈区(stack)概述:栈是向低地址扩展的数据结构,是一块连续的内存区域。由栈顶的地址和栈的最大容量是系统预先规定好的。栈的空间很小,大概1-2M。超出overflow。使用:栈区,就是函数(方法)运...
没有更多推荐了,}

我要回帖

更多关于 内存优化级别禁用好吗 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信