2011-07-13 53 views
1

我創建了一個從plist文件加載字典項目的小類。 getSettingForKey方法在我第一次調用靜態方法時工作,但是在多次調用之後,字典會針對使用與先前調用相同的密鑰的調用引發SIGABRT異常。有任何想法嗎?Objective-C靜態字段問題

static NSDictionary *dictionary = nil; 
static NSLock *dictionaryLock; 

@implementation ApplicationSettingsHelper 

+ (void) initialize 
{ 
    dictionaryLock = [[NSLock alloc] init]; 

    // Read plist from application bundle. 
    NSString *path = [[NSBundle mainBundle] bundlePath]; 
    NSString *finalPath = [path stringByAppendingPathComponent:@"Xxxx.plist"]; 
    dictionary = [NSDictionary dictionaryWithContentsOfFile:finalPath]; 

    // dump the contents of the dictionary to the console. 
    for(id key in dictionary) 
    { 
     NSLog(@"bundle: key=%@, value=%@", key, [dictionary objectForKey:key]); 
    } 
} 

+ (NSDictionary *)dictionaryItems 
{ 
    [dictionaryLock lock]; 

    if (dictionary == nil) 
    { 
     [self initialize]; 
    } 

    [dictionaryLock unlock]; 

    return dictionary; 
} 

+(id)getSettingForKey:(NSString *)key 
{   
    return [[self dictionaryItems] objectForKey:key]; 
} 

@end 

摩西 - 我已經採取了你的建議,並更新爲使用而不是NSUserDefaults的:

+ (void)load 
{ 
    // Load the default values for the user defaults  
    NSString* pathToUserDefaultsValues = [[NSBundle mainBundle] 
              pathForResource:@"Xxxx" 
              ofType:@"plist"]; 

    NSDictionary* userDefaultsValues = [NSDictionary dictionaryWithContentsOfFile:pathToUserDefaultsValues]; 

    // Set them in the standard user defaults 
    [[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsValues]; 
} 

+ (id)getSettingForKey:(NSString *)key 
{   
    return [[NSUserDefaults standardUserDefaults] valueForKey:key]; 
} 
+2

你知道,有一個名爲NSUserDefaults的類可能會實現你想要的。 – Moshe

+0

是的,我爲我的用戶應用程序設置使用NSUserDefaults。爲了閱讀一些配置url和非用戶設置,我只想從plist文件中讀取它們。 – mservidio

回答

8

你的字典可能已被釋放,從而導致無效的內存訪問。當您使用dictionaryWithContentsOfFile:方法創建字典時,它會自動發佈,這意味着它將在未來自動發佈。由於你永遠不會保留字典,該版本將導致字典被釋放。

此外,您的dictionaryItems方法大部分是無用的。

[dictionaryLock lock]; 
if (dictionary == nil) { 
    [self initialize]; 
} 
[dictionaryLock unlock]; 

+initialize方法由運行時自動調用叫上你的類的任何其他方法之前,除非你有一個+load方法。由於運行時會爲你調用它,它會嘗試創建字典,如果沒有足夠的內存來創建字典,字典只能在dictionaryItems方法中爲零,在這種情況下,它將再次失敗。另外,如果你不在別的地方使用鎖,那也是不必要的,因爲移除該檢查會導致它被鎖定並立即解鎖。因此,你可以刪除該鎖並改變你的dictionaryItems方法簡單:

+ (NSDictionary *)dictionaryItems { 
    return dictionary; 
} 
+0

感謝您的回覆。我通常在做C#並且不必擔心垃圾收集。 – mservidio

+0

規則很簡單。沒有理由因爲「我不習慣它」而忽視它們。任何時候你調用'alloc','new','copy'或'retain',你都需要釋放內存。 「autorelease」調用告訴應用程序在下一次自動釋放池消耗時釋放內存。通常,自動釋放對象保證可用,直到方法調用結束,但不再有更多。 – Moshe

2

除了@ ughoavgfhw的答案,你也初始化dictionaryLock後,可以有效地防止它。除非你在其他地方初始化dictionaryLock,否則我驚訝你的代碼越來越大。

編輯:我從@ ughoavgfhw的編輯看到+initialize在別的之前被調用,所以你的鎖在那裏被初始化。