2012-02-07 149 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