Использование NSUserDefaults для сохранения массива - PullRequest
1 голос
/ 01 ноября 2011

Я следовал за ответом на этот вопрос ( Как сохранить данные для закладок? ), чтобы сохранить закладки в NSUserDefaults.Это довольно просто, и это работает правильно в первый раз (когда нет записи в списке).Но затем он пытается скопировать ранее сохраненные закладки в новое 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 ]

3 голосов
/ 01 ноября 2011

Это неверно:

// 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 или сборщик мусора и вам не нужно об этом беспокоиться).

2 голосов
/ 01 ноября 2011

Вещи, возвращаемые из NSUserDefaults, всегда неизменяемы, независимо от того, были ли они изменяемыми до того, как вы их сохранили.

initWithCapacity:

определяется только для NSMutableArray, но не для NSArray.

Edit: Похоже, вы также дважды инициализируете свой объект:

// 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];
...