IOS自动有了ARC机制后,以及主流iphone设备不断扩大的内存,让开发者可以不像以前那样严格的考虑内存问题了。但是作为一个开发者,我们还是要尽可能的要写出合理使用内存的程序,尤其在调用某些第三方、开源的API、加载图片等资源文件、处理音视频等场景时,建议大家还是多多注意下。因为ARC下一旦出现内存问题,将更加难以定位与发现,有时即使leak工具也无法发现;此文便是汇总了开发中以及自己在实际的文档搜索中,总结的关于内存管理的一些使用技巧,便于查阅。
1、加载图片的方法:
[UIImage imageNamed:]只适合与UI界面中的贴图的读取,较大的资源文件应该尽量避免使用,用UIImage加载本地图像最常用的是下面三种:
(1) 用imageNamed方法:
[UIImage imageNamed:ImageName];
(2) 用 imageWithContentsOfFile 方法:
NSString *thumbnailFile = [NSString stringWithFormat:@"%@/%@.png", [[NSBundle mainBundle] resourcePath], fileName];
UIImage *thumbnail = [UIImage imageWithContentsOfFile:thumbnailFile];
(3)用initWithContentsFile方法
UIImage *image = [[UIImage alloc] initWithContentsOfFile:filePath]
第一种方法为常见方法,利用它可以方便加载资源图片。用imageNamed的方式加载时,会把图像数据根据它的名字缓存在系统内存中,以提高imageNamed方法获得相同图片的image对象的性能。即使生成的对象被 autoReleasePool释放了,这份缓存也不释放。而且没有明确的释放方法。如果图像比较大,或者图像比较多,用这种方式会消耗很大的内存。第二种方法加载的图片是不会缓存的。得到的对象时autoRelease的,当autoReleasePool释放时才释放。第三种方法要手动release掉。不进行系统缓存。release后立即释放,一般用在封面等图比较大的地方。
2、滑动列表的时候,使用UITableView的reuse机制
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
}
dequeueReusableCellWithIdentifier 方法会把隐藏的界面拿来重用,这样节省很多资源。
3、要大量创建局部变量的时候,可以创建内嵌的autorelease pool来及时释放内存
int main (int argc, const char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int i, j;
for (i = 0; i < 100; i++ )
{
NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
for (j = 0; j < 100000; j++ )
[NSString stringWithFormat:@"1234567890"];//产生的对象是autorelease的。
[loopPool release];
}
[pool release];
return 0;
}
4、循环引用带来的内存泄露。循环引用指两个对象相互引用了对方,从而导致谁也释放不了谁,导致内存泄露。例如声明一个delegate时,一般用assign而不是retain或者strong,因为delegate很容易引起循环引用。出现循环引用的场景还有block语句,例如:
self.myblock = ^{
[ self doSomething];
};
__block TestCycleRetain *weakSelf =self;
self .myblock = ^{
[weakSelf doSomething];
};
以下写法则不会出现循环引用:
//不会循环引用
__weak TestCycleRetain *weakSelf = self ;
self .myblock = ^{
[weakSelf doSomething];
};
//不会循环引用
__unsafe_unretained TestCycleRetain *weakSelf = self ;
self .myblock = ^{
[weakSelf doSomething];
};
参考资料:
(1)http://www.chengxuyuans.com/iPhone_IOS/67181.html
(2)http://www.cnbluebox.com/?p=255