【问题标题】:iPhone +NSCoding/NSKeyedArchiveriPhone +NSCoding/NSKeyedArchiver
【发布时间】:2010-10-18 10:57:30
【问题描述】:

我在坚持我的 App Settings 类时遇到了 NSCoding 和 NSKeyedArchiver 的一个小问题,我希望有人能发现问题,如果这是我的代码,我对 Obj-C 相对较新,但在多种语言方面拥有丰富的编码经验,所以代码对我来说似乎还可以,但是...

我有一个实例类来保存我的应用程序设置,该类本身是主应用程序委托的保留属性,这是通过一个

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

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

这是在 applicationDidFinishLaunching 事件中创建的:

settings = [Settings LoadSettings];

如果我注释掉上面的行,那么应用程序每次都可以正常工作,但是如果我使用 NSCoder 和 NSKeyedUnarchiver 从持久设置中拉回对象,则会抛出 SIGARBT 错误,因为正在发送 NSCFString 选择器以获取编码为布尔属性?设置类被定义为实现协议的 NSObject。

@interface Settings : NSObject <NSCoding>

正如我所说,创建设置类的实例很好,没有问题,保存它似乎还可以,并且从 LoadSettings 方法检查返回的类显示正确的值,只有在退出该方法后才会达到预期的效果bool 值似乎作为 NSCFString 被发送到 load 方法

- (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 App[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"];
}

Load 是一个静态方法,Settings 的所有其他成员都是实例。

【问题讨论】:

    标签: iphone


    【解决方案1】:

    你需要做的:

    settings = [[Settings LoadSettings] retain];
    

    那是因为在您的 LoadSettings 中,NSKeyedUnarchiver 的结果是一个自动释放的对象。然后它被释放了 :-) 在那个位置创建了一个新对象,在这种情况下是一个 NSString。

    编辑:

    好吧,我刚注意到我一开始错过的 LoadSettings 的一个主要问题:你混合了内存释放策略:在一个代码路径中,你返回 [[Settings alloc] init] 的结果 not 自动释放,而在另一个你保留 NSKeyedArchiver 的结果 自动释放。您需要确保只使用一个概念。

    由于方法名称 LoadSettings 的名称中不包含 alloccopynew,因此约定是它应该返回一个自动释放的对象。因此,您应该这样做:

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

    【讨论】:

    • 太好了,谢谢!我认为通过将静态 LoadSettings 方法返回的指针分配给应用程序委托中的保留指针,无论它的初始版本类型如何,它都会被保留。现在我对 iPhone 上的内存管理策略有了更多了解(我认为)。
    猜你喜欢
    • 2011-04-14
    • 1970-01-01
    • 1970-01-01
    • 2011-06-23
    • 1970-01-01
    • 2011-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多