2012-02-07 107 views
3

我正在使用的应用程序相对简单,但它引发了内存警告。我试图弄清楚应用程序设计是否需要太多内存,应该重新分配和分解以减少使用,或者应用程序设计没问题,但是应用程序本身臃肿,不正确地吞噬了超过所需内存的内存。iPad内存限制

该应用程序从Web下载包含一组问题的XML文件,然后生成显示问题控件列表的UIScrollView。每个问题控件都有一个UITextView和一个UISegmentedControl,UIButton,UITableView,UITextField或四个带有UIButton(自定义日期控件)的UITextFields。下面是截图:

http://i.imgur.com/vpa9Z.png

这种设置的伟大工程,对于较小的问题集,但应用程序开始投掷内存警告较大的套120的问题。这里是一个更大的集划分和VM跟踪仪器的典型运行:

http://i.imgur.com/gyWOX.png

对XML下载和型号的负载,但警告不抛出,直到分配的内存已经趋于稳定后,分配的内存峰值。虚拟机跟踪器内存在被抛出时仍然在增加,这让我认为控件仍然被加载到内存中,并且虚拟机跟踪器是导致警告的内存增长的更好指标。当Resident Size大于125 MB时,警告通常会发生。 我发现了一种方法来相当大地降低居民身材。问题控件具有自定义视图,以使它们具有圆角边缘和投影。如果我从自定义视图中注释掉drawRect代码(如下所示),则分配内存保持不变,但常驻大小下降大约30 MB,并且不会增长到93 MB以上。我可以找到问题的轻松背景,但如果我可以减少内存占用,我宁愿保留圆角边缘并投下阴影。

- (void)drawRect:(CGRect)rect { 
    // get the contect 
    CGContextRef context = UIGraphicsGetCurrentContext(); 

    //for the shadow, save the state then draw the shadow 
    CGContextSaveGState(context); 
    CGContextSetShadow(context, CGSizeMake(4,-5), 10); 

    //now draw the rounded rectangle 
    CGContextSetStrokeColorWithColor(context, [[UIColor blackColor] CGColor]); 

    if(_HighlightColor==nil){ 
     _HighlightColor = [[UIColor whiteColor] retain]; 
    } 
    CGContextSetFillColorWithColor(context, _HighlightColor.CGColor); 

    //since I need room in my rect for the shadow, make the rounded rectangle a little smaller than frame 
    CGRect rrect = CGRectMake(CGRectGetMinX(rect), CGRectGetMinY(rect), CGRectGetWidth(rect)-30, CGRectGetHeight(rect)-30); 
    CGFloat radius = 5; 
    // the rest is pretty much copied from Apples example 
    CGFloat minx = CGRectGetMinX(rrect), midx = CGRectGetMidX(rrect), maxx = CGRectGetMaxX(rrect); 
    CGFloat miny = CGRectGetMinY(rrect), midy = CGRectGetMidY(rrect), maxy = CGRectGetMaxY(rrect); 

    // Start at 1 
    CGContextMoveToPoint(context, minx, midy); 
    // Add an arc through 2 to 3 
    CGContextAddArcToPoint(context, minx, miny, midx, miny, radius); 
    // Add an arc through 4 to 5 
    CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius); 
    // Add an arc through 6 to 7 
    CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius); 
    // Add an arc through 8 to 9 
    CGContextAddArcToPoint(context, minx, maxy, minx, midy, radius); 
    // Close the path 
    CGContextClosePath(context); 
    // Fill & stroke the path 
    CGContextDrawPath(context, kCGPathFillStroke); 

    //for the shadow 
    CGContextRestoreGState(context); 
} 

仪器和内存警告使它看起来像内存刷爆了,但这些数字似乎很高我。我不认为在scrollview中这些问题控件中的120个会成为iPad处理的问题,但我没有一个关于他们应该使用多少内存的参考框架。考虑到一些iPad可以运行的图形密集型游戏,似乎上面的简单drawRect代码在问题控件中会占用超过30 MB的空间。这种内存使用量看起来很高,或者这是您对这个许多简单的UI元素的应用程序所期望的吗? drawRect中是否有东西会消耗大量的内存或关于如何优化它的任何建议?如果看起来这样会使iPad的内存最大化,我会创建标签或页面,并限制我放到标签页上的问题数量,这样一次只能将一小部分控件加载到内存中。不过,如果iPad应该能够在内存中处理它们,我宁可不打破它们。任何输入是不胜感激。

回答

4

您分配的每个视图都会占用大量内存。当屏幕上有很多视图(或滚动视图中的屏幕外)时,避免使用大量内存的方法是让您可以重复使用一个视图池,随时在屏幕上显示多个视图。

坏消息:这种缓存和交换设置起来相当复杂。

好消息:UITableView为您做到了!

当您拥有大量的UIViews时,最好的解决方案几乎总是将它们放到一个表格视图中,并让苹果公司努力工作。

+0

所以你认为我说的视图的数量可能会真实地用尽这么多的内存?我已经考虑过你提出的观点,但是认为它会持续不断地弄清哪些视图需要加载和卸载会很慢并且过于复杂。伟大的想法在UITableView!这将处理第二个问题。希望视图生成足够轻以便跟上滚动。我会给它一个镜头,让你知道。谢谢! – Wes 2012-02-07 07:50:04

+0

@Wes Views占用了相当多的内存;我相信每个人都拥有合成所有像素的缓冲区。如果您的视图生成速度非常慢,您可以为每种类型的行赋予自己的标识符(使用initWithStyle:Identifier:和deque ... WithIdentifier :)。这样,你只需要几次生成每种类型,剩下的时间只需填写数据。我从来没有尝试嵌套的tableviews,但我不明白为什么它不应该工作。 – cobbal 2012-02-07 07:54:54

2

您可以使用heap shot analysis(使用仪器)来监视内存变化,直到分配回溯细节 - 这应该给你足够的关于增长和原因的想法。这些拨款通常表明你在这段期间应该销毁的东西。

还要确保你的程序没有泄漏。

+1

感谢您的建议。我已经用它来将内存降到现在的位置,这是一个非常有用的工具。希望有人不知道它会看到你的帖子,并给它一个镜头。 – Wes 2012-02-07 07:55:03