使用NSUserDefaults保存数组

时间:2011-11-01 19:09:37

标签: objective-c arrays plist nsuserdefaults

我正在关注此问题(How To Save Data For Bookmarks?)的答案,以将书签保存到NSUserDefaults。它非常简单,并且它第一次正常工作(当plist中没有条目时)。但之后它会尝试将之前保存的书签复制到新的NSMutableArray应用程序崩溃中:

 *** Terminating app due to uncaught exception 'NSInvalidArgumentException', 
reason: '*** -[NSMutableArray initWithCapacity:]: 
method only defined for abstract class.  Define -[__NSArrayM initWithCapacity:]!'

这是我的代码(稍加修改):

-(void) addStationToFavorites{

    // Get the user defaults object
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    NSString *userSelectedService = [userDefaults objectForKey:@"idBikeServiceProvider"];

    // Load your bookmarks (editable array)
    NSMutableArray *bookmarks = [[NSMutableArray alloc] initWithCapacity:100];
    NSArray *bookmarksLoaded = [userDefaults arrayForKey:[NSString stringWithFormat: @"favStationForService%@",userSelectedService]];
    if (bookmarksLoaded != nil) {
        [bookmarks initWithArray:bookmarksLoaded];
    } else {
        [bookmarks init];
    }

    // Add a bookmark
    NSMutableDictionary *bookmark = [NSMutableDictionary new];
    [bookmark setValue:pass_stationName forKey:pass_stationId];
    [bookmarks addObject:bookmark];

    // Save your (updated) bookmarks
    [userDefaults setObject:bookmarks forKey:[NSString stringWithFormat: @"favStationForService%@",userSelectedService]];
    [userDefaults synchronize];

    // Memory cleanup
    [bookmarks release];

    //Show feedback
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@""
                                                    message:@"Added!"
                                                   delegate:self
                                          cancelButtonTitle:@"Ok"
                                          otherButtonTitles:nil];
    [alert show];
    [alert release];

}

2 个答案:

答案 0 :(得分:3)

这是不正确的:

// Load your bookmarks (editable array)
NSMutableArray *bookmarks = [[NSMutableArray alloc]initWithCapacity:100]; // OK
NSArray *bookmarksLoaded = [userDefaults arrayForKey:[NSString stringWithFormat: @"favStationForService%@",userSelectedService]];
if (bookmarksLoaded != nil) {
    [bookmarks initWithArray:bookmarksLoaded]; // NOT AGAIN
} else {
    [bookmarks init]; // NOT AGAIN
}

不要在对象上多次调用init方法。我怀疑这是你的错误的来源,因为NSArray / NSMutableArray被实现为"类集群"并且initWithCapacity:返回的确切类不是NSMutableArray,而是一些私有子类,它抱怨第二次初始化。这是实现相同目标的更好方法:

// Load your bookmarks (editable array)
NSMutableArray *bookmarks;
NSArray *bookmarksLoaded = [userDefaults arrayForKey:[NSString stringWithFormat: @"favStationForService%@",userSelectedService]];
if (bookmarksLoaded != nil) {
    bookmarks = [bookmarksLoaded mutableCopy];
} else {
    bookmarks = [[NSMutableArray alloc] initWithCapacity:100];
}

当您需要不可变容器对象的可变版本时,mutableCopy方法非常有用。请注意,因为" copy"在方法名称中,您拥有结果并且必须稍后释放(除非您使用ARC或垃圾收集并且不需要担心它)。

答案 1 :(得分:2)

从NSUserDefaults返回的内容总是不可变的,无论它们在存储之前是否可变。

  

initWithCapacity:

仅在NSMutableArray上定义,而不在NSArray上定义。

编辑: 您似乎也在初始化对象两次:

// Load your bookmarks (editable array)
    NSMutableArray *bookmarks = [[NSMutableArray alloc]initWithCapacity:100];
    NSArray *bookmarksLoaded = [userDefaults arrayForKey:[NSString stringWithFormat: @"favStationForService%@",userSelectedService]];
    if (bookmarksLoaded != nil) {
        [bookmarks initWithArray:bookmarksLoaded];