2011-03-31 51 views
0

我有一個模型類,保持跟蹤記錄由多個視圖構建。它有一個NSMutableDictionary,它有我最終寫入數據庫的字段和值。它被保存到plist並在需要時裝回。我以爲我記錄了我的記憶,但是當我嘗試發佈字典時,它會拋出EXC_BAD_ACCESS。這是我的接口:Objective C NSMutableDictionary內存管理

#import <Foundation/Foundation.h> 


@interface CurrentEntryModel : NSObject { 
NSMutableDictionary *currentEntry; 
} 

@property (nonatomic, retain) NSMutableDictionary *currentEntry; 
- (void) setValue: (NSString *)value; 
- (NSString *) getValue; 

@end 

我的理解是currentEntry應該保留,我將不得不在dealloc期間釋放它。

這裏是我的實現(這是不是整個類只是相關部分):

#import "CurrentEntryModel.h" 


@implementation CurrentEntryModel 

@synthesize currentEntry; 

-(id) init { 
    if (self = [super init]) 
    { 
    //check for file 
    NSFileManager *fileManager = [NSFileManager defaultManager]; 
    NSString *file; 
    file = @"location.plist"; 

    if ([fileManager fileExistsAtPath:file]){ 
     NSLog(@"file exists"); 
     currentEntry = [[NSMutableDictionary alloc] initWithContentsOfFile:file]; 

    }else { 
     NSLog(@"file doesn't exist"); 
     currentEntry = [[NSMutableDictionary alloc ] initWithCapacity:1]; 

     NSDate *testDate = [NSDate date]; 

     [currentEntry setObject:testDate forKey:@"created"]; 

     [currentEntry writeToFile:file atomically:YES]; 

    } 

} 
return self; 
} 

- (void) setValue: (NSString *)value { 
[currentEntry setObject:value forKey:@"location"]; 
} 

- (NSString *) getValue { 
return [currentEntry objectForKey:@"location"]; 
} 


- (void) dealloc{ 
[currentEntry release]; 
[super dealloc]; 

} 

@end 

如果我初始化這個類會自動創建字典,如果我叫組的一個或得到它看起來像字典保留,因爲它會正確釋放。如果該類剛剛初始化,然後沒有方法被調用,它將拋出EXC_BAD_ACCESS錯誤。如果我沒有錯誤,當文件不存在時,我不正確地初始化字典,因爲該方法以字典而不是初始化開始。雖然每次運行該文件時都會使用該文件,但我認爲這將保留該變量。

我不正確初始化字典嗎?

編輯 - 更改便利方法上的代碼以反映正確的方式。每個人都注意到Squeegy必須說的話。

+0

我欣賞關於類方法的信息,但是我在我的問題中已經說過,這不是錯誤的來源 - 「雖然每次運行此文件時都會使用文件找到的邏輯,而我認爲這將保留變量'。有沒有人有任何想法? – Joshua 2011-04-07 01:51:01

回答

2

這是壞壞壞。

else { 
     NSLog(@"file doesn't exist"); 
     currentEntry = [[NSMutableDictionary alloc ] dictionaryWithCapacity:1]; 

dictionaryWithCapacity:NSMutableDictionary一類方法,它返回一個自動釋放的對象,而你沒有retain它。所以運行循環結束,字典被自動釋放。然後你在你的dealloc中運行[currentEntry release],它會爆炸,因爲該對象已被釋放。

您可能不想用initWithCapacity:代替。始終將alloc與以init開頭的方法配對。


此外,當使用像這樣的保留屬性時,我通常讓屬性找出這個對我來說,只適用於自動釋放對象。你只需要記住更少的規則,並且有更少的陷阱。

- (id)init { 
    // ... 
    self.currentEntry = [NSMutableDictionary dictionWithContentsOfFile:file]; 
    // ... 
} 

- (void)dealloc { 
    //... 
    self.currentEntry = nil; 
    //... 
} 

這種方式,你從來沒有打電話retainrelease直接在物體上。根據我的經驗,這會導致更少的混淆錯誤。但這也是許多ObjC程序員的風格,並非所有人都同意。

+0

是的,我今天發現了這一點,並在研究答案時引用了我的問題。我讀過的大多數教程都沒有提及便捷方法autorelease,而且您需要使用以init開頭的內容。我確實改變了這一點,它仍然會拋出EXC_BAD_ACCESS錯誤。 – Joshua 2011-03-31 23:31:15

+0

從內存管理規則:「就像你不應該關心對象的實際保留數量一樣,你不應該關心返回給你的對象是否被自動釋放,唯一的問題是,你是否擁有它或不。」假定返回給你的對象是自動釋放的,這是有點不利的。特別是,'[NSNumber numberWithInt:0]'會給你一個你不擁有的對象,但是一個通常不會自動釋放的對象(它通常被緩存)。 – dreamlax 2011-03-31 23:35:29

+0

這是一個很好的觀點。 'init','retain'或者屬性賦值都意味着「我擁有這個」。 – 2011-04-01 00:23:56

0

約書亞 -

+ (id)dictionaryWithCapacity:(NSUInteger)numItems 

是NSDictionary中的類的方法。所以,當你調用它,它應該是:

[NSMutableDictionary dictionaryWithCapacity:1]; 

不:

[[NSMutableDictionary alloc] dictionaryWithCapacity:1]; 

此外,[的NSMutableDictionary dictionaryWithCapacity:]返回一個自動釋放的對象。如果你想保持字典作爲伊娃,而不是讓它自動釋放對運行循環的下一個循環,你應該叫:

[currentEntry retain]; 

所以,基本上,將其更改爲:

currentEntry = [[NSMutableDictionary alloc] initWithCapacity:1]; 

或:

currentEntry = [[NSMutableDictionary dictionaryWithCapacity:1] retain]; 

第一種可能更有意義,因爲設計的connivence類的方法,當你想要一個自動釋放的情況下使用。

+0

不要對從類方法返回的對象是否是「自動釋放」做出假設,而應該只關心您是否擁有該對象。根據內存管理規則:「正如你不應該關心對象的實際保留計數一樣,你不應該關心返回給你的對象是否被自動釋放,唯一的問題是,你擁有它還是不。」 – dreamlax 2011-03-31 23:32:39