2010-01-16 58 views
0

我是iphone開發新手。我是「老學校」 - 在編程時我習慣使用程序等。現在一切都是面向對象的,但我的風格依然如此。請記住這一點。我的項目很小,實際上只是一個概念證明。從Plist詞典顯示隨機單詞 - 內存泄漏?

下面的程序在計時器上工作 - 每隔30秒它會從我的應用程序中存儲在Dictionary.plist中的名稱數據庫列表中讀取一個隨機寶寶名稱。然後在iphone屏幕上顯示這個名字。

你可以看到下面的代碼的完整的相關部分。 會發生什麼 - 如果我增加計時器以非常快的速度運行 - 最終它似乎耗盡內存或其他東西,因爲它只是顯示?而不是下一個隨機寶貝的名字。 我懷疑這是由於我每次讀它都沒有關閉數據庫文件。

無論如何,有人可以看看我的代碼(與我的上述意見考慮),並告訴我,我需要添加什麼來阻止它顯示?這麼多的運行後..

我只是每次打開文件ShowNextName因爲我不能想出另一種方式來做到這一點..

我知道它不是偉大的風格在此開始使用變量代碼是全球等,但有沒有可能重組或增加一些東西,以阻止它「崩潰」或在這麼多次運行後有點搞笑的方式...

我會很感激。謝謝。

#import "BabyNameViewController.h" 

@implementation BabyNameViewController 


NSDictionary *dictionary; 
NSString *name; 

int nameCount = 0; 
int RecordIndex = 0; 


- (void)ShowNextname; 
{ 
    NSString *path = [[NSBundle mainBundle] bundlePath]; 
    NSString *finalPath = [path stringByAppendingPathComponent:@"Dictionary.plist"]; 
    NSArray* plistArray = [NSArray arrayWithContentsOfFile:finalPath]; 

    // Generate a random number between 0 and (the number of records-1) - used as a random index! 

    RecordIndex=arc4random()%[plistArray count]; 


    // Select and display currently selected record from the array. 
    dictionary = [plistArray objectAtIndex:RecordIndex]; 
    name = [dictionary objectForKey:@"name"]; 

    [nameLabelOutlet setText: [NSString stringWithFormat: @"Random Baby Name is: %@", name]]; 

} 

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. 
- (void)viewDidLoad { 
    [super viewDidLoad]; 

// Initial App entry point - startup code.. 


// Open the dictionary to count the number of names and store it for later use. 
NSString *path = [[NSBundle mainBundle] bundlePath]; 
NSString *finalPath = [path stringByAppendingPathComponent:@"Dictionary.plist"]; 
NSArray* plistArray = [NSArray arrayWithContentsOfFile:finalPath]; 
nameCount = [plistArray count]; 

// Generate random name from database 
[self ShowNextname]; 

// Start up the nameUpdate timer. 
[NSTimer scheduledTimerWithTimeInterval:30 target:self selector:@selector(nameUpdate) userInfo:nil repeats:YES]; 

}

-(void) nameUpdate { 
    [self ShowNextname]; 
} 

回答

1

的問題可能是每30秒您正在重新加載的plist到一個新的數組。你應該做的是在viewDidLoad中將plist加載到對象(你的視圖控制器類)中的一個實例變量中,然後在showNextName中使用該實例變量。 (另外,我會一直以小寫字母和大寫字母開頭的方法,或者人們可能會認爲ShowNextname是一個類而不是一個方法。)

也不要忘記添加[plistArray release];你的dealloc方法。

這裏有一個很好的免費文件,你可能需要閱讀,可以幫助一些:

http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/OOP_ObjC/Introduction/Introduction.html

+0

謝謝 - 現在閱讀該文檔。是的,這是問題 - 我每次都會將plist重新加載到一個新陣列中。我知道你在說什麼,但不知道實現它的語法 - 你可能會告訴我要使用的代碼行,它將視圖控制器中的plist加載到實例變量中 - 我將它放在哪裏在showNextName中? 我會改變我的代碼風格,重新評論類/方法,並在最後解除分配。謝謝你的幫助。 – 2010-01-16 00:46:54

+0

在括號內的.h中聲明'plistArray'。這將使它成爲一個實例變量,您可以從類中的任何'-'方法訪問它。 – 2010-01-16 00:58:58

+0

就像弗蘭克說的那樣,但是當你設置實例變量以確保它沒有獲得空閒()d時,你應該真的做一個[plistArray retain]。 (方法'retain'和'release'遞增或遞減一個引用計數,當count數降到0時,會導致free()被調用,因爲你有一個引用,所以你想增加count。)另見http:/ /developer.apple.com/mac/library/documentation/cocoa/Conceptual/ObjectiveC/Articles/ocProperties.html,它會告訴你如何聲明一個帶有'retain'關鍵字的屬性將有助於維護你的引用計數。 – Nimrod 2010-01-16 01:36:00

1

你有額外的間接層:你可以這樣做:

[NSTimer scheduledTimerWithTimeInterval:30 target:self selector:@selector(ShowNextName) userInfo:nil repeats:YES]; 

和消除nameUpdate方法。

1

關於過渡到對象的建議 - 有助於思考像結構這樣的對象,您也可以使用方法。實例變量就像結構中的項目,您需要一個特定的結構(類實例)才能獲得正確的值 - self只是一種方法來查看自己類中保存的值。因此,視圖控制器中的方法都在查看一個類實例,即創建用於顯示視圖的視圖控制器。

另外思考內存的方法是這樣的,當你分配一個實際上就像malloc一樣的對象時 - 任何flavor的init都像在結構中設置初始值(因爲malloced內存可以是任何最初的東西) 。然後在釋放後釋放分配的內存,但只有在沒有任何保留呼叫時。保留與計數器一起使用的記憶blocvk的標記,並釋放遞減計數器 - 當它到達0時,記憶消失。這是一個簡化的視圖,但可以幫助你開始。

0

如果您的應用程序不斷使用更多內存,請在「儀器(泄漏模板)」下運行該程序,並查看所有內存正在進入的位置。然後,深入研究總體規模不斷增長的類,並查看分配事件發生的位置。然後,你將能夠找到你違反的地方the memory management rules

我看不出任何此類違規行爲,因此問題必須出現在其他地方。儀器將幫助您找到它。

This video可能會幫助你。

+0

謝謝彼得這非常有幫助。 – 2010-01-17 00:19:14