您的位置:首页 > 移动开发 > IOS开发

iOS开发内存管理总结

2017-02-10 12:02 260 查看
一、retain、copy、assign的区别:1.retain:当对一个对象A调用retain,然后赋值给B时,对象的引用计数加1,A和B指向同一个内存地址。2.copy:当对一个对象A调用retain,然后赋值给B时,对象的引用计数加1,而且生成了一个新的拷贝,A和B指向不一样的内存地址。3.assign:当对一个对象A调用retain,然后赋值给B时,对象的引用计数不变,A和B指向同一个地址。
二、为什么delegate声明要使用assign?因为如果使用assign的话,对象间会产生循环引用的情况,导致循环引用的对象都不能释放内存。
三、atomic和noatomic的区别这两个关键字用来决定编译生成的getter和setter方法是否为原子操作,即是否是多线程安全的。atomic表示是原子操作,支持多线程安全,noatomic是非原子操作,不支持多线程安全。
四、自动释放池1.自动释放池实现了对象的延迟释放,将释放时机延后。当对一个对象调用autorelease方法后,对象被加入自动释放池。当自动释放池释放时,会对自动释放池中的对象调用release方法。2.主线程会自动创建自动释放池,自己创建的线程需要自己负责创建自动释放池。在一个RunLoop周期开始时,系统会创建一个自动释放池,当RunLoop周期结束时,系统会释放之前创建的自动释放池。如果我们在使用autorelease时没有自己创建自动释放池,对象会在它所在的RunLoop周期结束时被释放掉。一个UI事件,Timer调用,delegate调用,都会是一个新的Runloop。3.类似于[NSString stringWithFormat:]这样的类方法创建的对象默认是使用了自动释放池的,不需要释放。4.当在短时间内大量的使用自动释放对象,要手动使用自动释放池来释放对象,否则内存会在短时间内疯涨。
六、didReceiveMemoryWarning、viewDidUnload和dealloc方法使用1.didReceiveMemoryWarning方法:首先调用[super didReceiveMemoryWarning]方法,然后检查当前视图的父视图是否为空,如果为空,则释放掉一些不需要的数据。关于视图界面的释放不应该在这个方法中,应该放在viewDidUnload方法中。2.viewDidUnload方法:(1)此方法只在发生内存警告时调用。在这个方法调用之前,控制器的view属性已经被release并且设置为nil。(2)iOS6之前:当低内存情况发生,而且当前视图不需要显示时,系统会调用此方法来清理额外的视图(但是控制器还存在)。在此方法中我们需要清理输出口,比如清理输出口:self.xxxx = nil;(使用self关键字);以及我们自己通过代码建立的视图界面。我们不应该在此方法中清除数据,尤其是一些不能恢复的数据。可以恢复的数据我们应该在didReceiveMemoryWarning中清除,不能恢复的数据应该在dealloc方法中清除。(3)iOS6以及之后:当控制器的视图已经没有显示在window上时,系统会自动清空控制器中的所有视图以及输出口,所以不用在发生内存警告时再调用此方法。所以,在iOS6以及以后的版本,这个方法不会再被调用了。3.dealloc方法:对象释放时调用,在这个方法中,要释放掉所有的数据和输出口。比如释放输出口:[xxx release];(不使用self关键字)
六、一些注意的地方1.向集合(NSArray,NSDictionary等)添加对象时,被添加的对象会被执行retain操作,当从集合中移走对象或者集合对象被释放时,集合中的对象会被执行release操作。2.要保证有多少个alloc、copy、multablecopy、retain消息,就要有多少个release或者autorelease,保证代码平衡。3.在程序中直接用@""创建的NSString对象,是常量,引用计数是-1,向它发送retain、release没有效果。4.在View中使用图片时,大的图片区域尽量使用小的图片数据来填充,减小内存占用。5.[UIImage imageNamed:@""],次方法使用了系统缓存来缓存图像,会长时间占用内存,最好使用imageWithContentsOfFile方法。6.数据要延迟加载,只在内存中保留满足需要的最少的数据和视图元素,需要的时候再加载,不需要就马上销毁。7.假如一个成员变量在property中使用了retain,当使用self关键字对其赋值时,会对创建的对象再retain一次,造成内存泄露。比如:self.xxx = [[XXX alloc] init];  对一个成员变量赋nil值时,self.xxx = nil,会调用xxx的release方法,并且将指针置空,xxx = nil,只是将指针置空。8.加载本地图片时,尽量不要使用[UIImage imageNamed:@""]这个方法,因为这个方法会使用系统缓存来缓存图像,会占用内存。可以使用[UIImage imageWithContentOfFile:@""]来加载本地图像。9.在控制器中使用NSTimer会使当前控制器引用计数加1,所以在控制器释放之前,必须暂停和使定时器失效,否则控制器将不会被释放。
七、内存警告(iOS6之前)1.原理:当发生内存警告时,系统会对程序内存在的所有的ViewController调用didReceiveMemoryWarning方法,然后,如果当前ViewController没有父视图(即没有显示),viewDidUnload方法会被调用(iOS6及以后不调用)。之后,当ViewController的视图对象,比如view,被再次访问时,viewDidLoad方法会被调用,一般视图初始化和数据创建都在viewDidLoad方法里面做,所以界面和数据会恢复。2.处理方法:(1)使用数据缓存机制:为每个ViewController创建一个数据缓存池,比如使用NSMultableDictionary类型,我们把所有可以重建的数据、动态创建的视图元素引用都保存在这个缓存池中,而且每组数据都用一个Key对应。如果缓存池中已经存在这组数据了,则直接取出来用,如果不存在,则创建再使用。(2)当发生内存警告时,如果当前视图在显示,则只清空数据,不清空视图元素引用,如果不在显示,则把数据和视图元素引用都清空。(3)发生内存警告后,当控制器的视图重新回到window显示时,viewDidLoad方法会被调用,界面和数据会恢复。(4)当控制器销毁时,在delloc方法中将数据缓存中的数据全部清空。(5)当需要重置缓存中的数据时,按照Key从缓存池中删除对应的数据,然后再按照第(1)条的规则取数据。3.遇到的问题:苹果推荐的didReceiveMemoryWarning的实现方式是这样:-----------------------------------------------------------(void)didReceiveMemoryWarning{    if (self.view.superview == nil) {            //在此处清空一些不需要的数据        }    [super didReceiveMemoryWarning];}----------------------------------------------------------假如此时这个视图控制发生了内存警告,数据和视图元素被释放了,然后在这个视图恢复显示之前,又发生了内存警告,就再次调用了此方法,因为在这个方法中访问了view属性,所以viewDidLoad方法会调用,视图和数据被重建,创建完之后,视图和数据又马上被清空。这个过程时多余的。4.解决办法:在控制器中设立一个变量,用来标志是否需要对内存警告做出响应,比如,isNeedCheckMemoryWarning,在viewDidLoad方法中将其设置为YES,在didReceiveMemoryWarning方法中检查这个值,代码如下:-----------------------------------------------------------(void)didReceiveMemoryWarning{    if (isNeedCheckMemoryWarning == YES && self.view.superview == nil) {        //在此处清空一些不需要的数据    }    isNeedCheckMemoryWarning = NO;    [super didReceiveMemoryWarning];}
八、内存警告(iOS6之后)1.不同之处:(1)iOS6之后viewDidUnload不再调用,当控制器的视图已经没有显示在window上时,系统会自动清空控制器中的所有视图以及输出口。(2)因为视图的释放由系统控制了,所以当发生内存警告之后,view被再次访问,viewDidLoad不再调用。(3)综合以上两点,所有关于界面的回收和恢复我们都可以不用管,包含动态创建的视图(可以恢复)。我们只需要关注数据。
2.处理方法与第七点的不同<1>同样使用数据缓存池,但是数据缓存池中只存储视图之外的数据。<2>数据缓存池的创建放到initXXX方法中,只创建一次。<3>第三点遇到的问题不存在了,可以不用加isNeedCheckMemoryWarning变量。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: