2010-10-18 50 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