2011-05-02 66 views
3

我試圖修復當我訪問tableView:cellForRowAtIndexPath:indexPath中的NSMutableDictionary時引發的EXC_BAD_ACCESS錯誤。現在,它的工作原理,當我填寫ridesDict與方法loadHistoryFromDBExtended像這樣:NSMutableDictionary導致EXC_BAD_ACCESS

self.ridesDict = [self loadHistoryFromDBExtended]; 

NSLog(@"rides dict %@", self.ridesDict); 

不過,我不想叫[自我loadHistoryFromDBExtended]對於每一個細胞都被加載,因爲字典也不會改變,所以我嘗試移動:

self.ridesDict = [self loadHistoryFromDBExtended]; 

到viewDidLoad中,現在我得到EXC_BAD_ACCESS錯誤,當我使用:

NSLog(@"rides dict %@", self.ridesDict); 
中的tableView

:的cellForRowAtIndexPath:indexPath。從我看過的內容看來,我有一些內存保留/釋放問題,但我似乎無法弄清楚。在loadHistoryFromDBExtended方法被調用後,我嘗試在viewDidLoad中使用[self.ridesDict retain],但這並沒有幫助。我對此非常陌生,所以我很欣賞任何指向哪裏。

編輯:這裏是loadHistoryFromDBExtended方法:

-(NSMutableDictionary *)loadHistoryFromDBExtended 
{ 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

    FMDatabase* db = [FMDatabase databaseWithPath:[self getDBPath]]; 

    if (![db open]) 
    { 
     NSLog(@"Could not open db."); 
     [pool release]; 
    } 

    //get users 
    FMResultSet *rs = [db executeQuery:@"SELECT * FROM R order by date desc"]; //query provides result set 

    //create result array 
    NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] init]; 

    while ([rs next]) 
    {   
     NSMutableArray *usersDictArray = [NSMutableArray array]; 

     //look up names for id's 
     [usersDictArray addObject:[rs stringForColumn:@"rNames"]]; 
     [usersDictArray addObject:[rs stringForColumn:@"dName"]]; 
     [usersDictArray addObject:[rs stringForColumn:@"date"]]; 
     [myDictionary setObject:usersDictArray forKey:[rs stringForColumn:@"rID"]]; 

     [usersDictArray release]; 
    } 

    //return usersArray; 
    return myDictionary; 

    [myDictionary release]; 

    [pool drain]; 
} 
+1

'loadHistoryFromDBExtended'是否返回調用者擁有的對象? 「ridesDict」的聲明是什麼?這是一個財產嗎?如果是這樣,它是「保留」還是「複製」屬性?您是否在爲該屬性使用合成訪問器,或者是否實施了自定義訪問器? – 2011-05-02 03:14:39

+0

loadHistoryFromDBExtended返回在​​該方法中聲明的myDictionary。 ridesDict在接口和@property中聲明(nonatomic,retain)NSMutableDictionary * ridesDict;在.h然後@synthesize ridesDict;在.m – 2011-05-02 15:56:36

回答

2

該方法如何實施有許多問題。在檢查db是否可以打開時,您釋放自動釋放池,但繼續執行其餘代碼。我想你可能想在這一點上返回nil。在[rs next]部分中,您將創建一個NSMutableArray,其中+array將創建一個自動釋放對象。因此,您不應該致電[usersDictArray release],因爲這將會過度釋放。 (在每個循環中,「臨時」,自動發佈的usersDictArray實例將存儲在pool自動釋放池中。當您調用[pool drain]時,自動釋放池將發送所有這些臨時實例(release消息)。最後,你有return myDictionary;,這導致未來2行永遠不會到達。因此,您創建的autorelease池永遠不會被釋放(彈出)。

這可能是我將如何實現它:

-(NSMutableDictionary *)loadHistoryFromDBExtended { 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

    FMDatabase* db = [FMDatabase databaseWithPath:[self getDBPath]]; 

    if (![db open]) 
    { 
     NSLog(@"Could not open db."); 
     [pool release]; 
     return nil; // I'm assuming you should return nil here 
    } 

    //get users; query provides result set 
    FMResultSet *rs = [db executeQuery:@"SELECT * FROM R order by date desc"]; 

    //create result array 
    NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] init]; 

    while ([rs next]) 
    {   
     NSMutableArray *usersDictArray = [NSMutableArray array]; 
     //look up names for id's 
     [usersDictArray addObject:[rs stringForColumn:@"rNames"]]; 
     [usersDictArray addObject:[rs stringForColumn:@"dName"]]; 
     [usersDictArray addObject:[rs stringForColumn:@"date"]]; 
     [myDictionary setObject:usersDictArray forKey:[rs stringForColumn:@"rID"]]; 
     // [usersDictArray release]; 
    } 
    [pool drain]; 
    return [myDictionary autorelease]; 
} 

(請注意,我是如何實現這個假設背後創建本地自動釋放池的理由是性能,而且有一個地方的全局NSAutoreleasePool吸收最終的[myDictionary autorelease]自動釋放對象)。

+0

正如Lou Franco的回覆中提到的,這確實解決了問題以及接下來我正在處理的泄漏問題。謝謝。 – 2011-05-02 21:32:14

4

我寫這個博客,以幫助理解和調試EXC_BAD_ACCESS

http://loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html

按照容易爲了

  1. 運行一個構建和分析 - 你有一個乾淨的構建?看看它在說什麼,但你現在可以忽略泄漏問題 - 尋找將消息發送到已發佈對象的問題

  2. 使用NSZombiesEnabled運行 - 這會使對象永不釋放,然後在發送消息時發出抱怨一個對象的retainCount爲0.

  3. 啓用Guard Malloc,然後使用特殊的GDB命令檢查堆的完整性。問題在於,您需要在崩潰之前逐步完成並找到真正的問題。它可能會崩潰別的地方更接近你的問題,但

+0

我不知道構建和分析。非常有幫助,謝謝。如果你看到我的原始評論,我添加了loadHistoryFromDBExtended方法,我發佈了我用來在每個循環上構建字典的數組。我認爲我有一種印象,我必須釋放它才能清除陣列,然後重新使用它。我仍然有漏洞,但現在它可以工作,我可以繼續前進。再次感謝。 – 2011-05-02 17:03:45

1

嘗試致電:

[self.ridesDict retain]; 

使用字典(也許在類初始化)前。不要忘了致電:

[self.ridesDict release]; 
self.ridesDict = nil; 

at dealloc。

另請檢查您是否正確聲明瞭標題中的屬性。它必須是:

@property (nonatomic, retain) NSMutableArray *ridesDict; 

並將@synthesize ridesDict;添加到您的類實現中。

+0

您需要知道@property是如何聲明的,以瞭解這是否正確。例如,如果是「保留」,則不應該這樣做。屬性分配會自動保留,並分配給nil,釋放舊對象。 – 2011-05-02 11:44:09

+0

但「忘記呼叫保留」這是分段故障(又名EXC_BAD_ACCESS)最常見的原因。同意你的看法,可能是因爲你錯誤地聲明瞭@property。我忘了它是類變量,我認爲(我不知道爲什麼)它是本地變量。但是,如果它是class var,我建議你在@property參數中添加保留 – HiTECNOLOGYs 2011-05-02 12:23:18