2010-10-18 53 views
1

我有一個NSCoding和NSKeyedArchiver的問題,當堅持我的應用程序設置類,並希望有人可以發現一個問題,如果它是我的代碼,我相對較新的Obj-C但有足夠的編碼經驗在衆多的語言,使代碼似乎確定我,但...iPhone + NSCoding/NSKeyedArchiver

我有一個實例類來保存我的應用程序設置,類本身是主要的應用代表的保留的性質,這是通過

創建
@interface AppDelegate : NSObject <UIApplicationDelegate> { 
    Settings *settings; 
    [...] 
} 

@property (nonatomic, retain) Settings *settings; 
[...] 

這是在applicationDidFinishLaunching事件中創建的:

settings = [Settings LoadSettings]; 

如果我註釋掉上面的線,則應用正常工作,每次,但是如果我拉oject背部使用NSCoder和NSKeyedUnarchiver持久設置,SIGARBT引發錯誤的NSCFString選擇什麼是被髮送編碼爲布爾屬性? Settings類被定義爲一個實現該協議的NSObject。

@interface Settings : NSObject <NSCoding> 

正如我說的,創造的設置類是精細的實例,也沒有問題,節約似乎OK以及檢查從LoadSettings方法顯示出正確的價值觀的迴歸類,退出後才方法並預期bool值似乎一旦設定已載入有關財產這樣使用是越來越發送到負載方法作爲NSCFString

- (id)initWithCoder:(NSCoder *)decoder { 
    if (self = [super init]) { 
      [...] 
     self.animateMenus = [decoder decodeBoolForKey:@"animateMenus"]; 
    } 

    return self; 
} 

- (void)encodeWithCoder:(NSCoder *)encoder { 
    [...] 
    [encoder encodeBool:animateMenus forKey:@"animateMenus"]; 
} 

SettingsViewController *settingsView = [[SettingsViewController alloc] initWithNibName:@"SettingsView" bundle:nil]; 
[self presentModalViewController:settingsView animated:[AppDelegate instance].settings.animateMenus]; 
[settingsView release]; 

**的設置類的animateMenus構件現在將拋出以下:

- [NSCFString animateMenus]:無法識別的選擇發送到實例0xc712570 2010-10-15 11:12:51.828應用[900:207] *終止應用程序,由於未捕獲的異常'NSInvalidArgumentException',原因:' - [NSCFString animateMenus]:無法識別的選擇器發送到實例0xc712570'

而'settings = [Settings LoadSettings];'調出應用程序啓動消除了這個問題(但是總是使用應用程序默認值)?

加載和保存方法:

+ (Settings*) LoadSettings { 
    Settings *s = nil; 

    @try { 
     NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:@"settings"]; 

     if (data == nil) { 
      s = [[Settings alloc] init]; 
      [s Initialise]; 
      [s SaveSettings]; 
     } 
     else 
      s = (Settings*)[NSKeyedUnarchiver unarchiveObjectWithData:data]; 
    } 
    @catch (NSException * e) { 
     NSLog(@"Error Loading Settings\n%@", [e reason]); 
    } 
    @finally { 
     return s; 
    } 
} 

// Saves the settings dictionary to the user's device documents folder.. 
- (void) SaveSettings { 
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self]; 
    [[NSUserDefaults standardUserDefaults] setObject:data forKey:@"settings"]; 
} 

負載是一個靜態方法設置的所有其他成員都是實例。

回答

0

你需要做的:

settings = [[Settings LoadSettings] retain]; 

這是因爲在你的LoadSettings,NSKeyedUnarchiver的結果是一個自動釋放的對象。它被釋放:-)在那個位置創建了一個新的對象,在這種情況下是一個NSString。

編輯:

嗯,我剛纔注意到一個重大問題,我錯過了在第一LoadSettings:你混的內存釋放策略:在一個代碼路徑返回的[[Settings alloc] init]其結果是自動釋放,而在另一個你保留NSKeyedArchiver的結果,其中自動釋放。您需要確保只使用一個概念。

由於方法名稱LoadSettings在其名稱中不包含alloccopynew,因此約定是它應該返回一個自動釋放對象。因此,你應該這樣做:

if (data == nil) { 
     s = [[Settings alloc] init]; 
     [s Initialise]; 
     [s SaveSettings]; 
     [s autorelease]; 
    } 
    else 
     ... 
+0

優秀,謝謝!我認爲,通過將靜態LoadSettings方法中的返回指針分配給應用程序委託中的保留指針,它將被保留,而不管它的初始版本類型如何。現在我明白了(我認爲)更多關於iPhone上的內存管理策略。 – 2010-10-18 13:00:31