从uitableview检索并重新保存nsmutablearray到nsuserdefaults

时间:2013-02-21 14:07:11

标签: ios objective-c uitableview nsmutablearray nsuserdefaults

我有一个uitableview,其中包含从应用程序中本地的JSON文件填充的项目列表。只要将列表添加到表中,并且选择(或取消选择)的项目的多个选择随后将保存到nsmutablearray中,一切都可以正常工作。

问题是当用户离开视图并返回并选择另一个项目(或取消选择当前选定的项目)时。此时,可变数组就是空的。

我不确定nsuserdefaults是否可以保存可变数组。它保存得很好,但是当视图重新出现时(此时可变数组的值很好)并且用户触摸表行,数组再次为空。

我的.h文件:

@interface CategoriesViewController : UITableViewController {

    NSMutableArray *_selectedItems;

    NSString *filePath;

    NSString *string;

}

// arForTable array will hold the JSON results from the api
@property (nonatomic, retain) NSArray *arForTable;

@property (nonatomic, retain) NSMutableArray *categorySelected;

@property (nonatomic, retain) NSString *jsonStringCategory;
@property(nonatomic, retain) UIView *accessoryView;

@end

我的.m文件:

@implementation CategoriesViewController
@synthesize arForTable = _arForTable;

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.categorySelected = [[NSMutableArray alloc] init];

    [self reloadMain];

    // assignment reference so don't release
     _selectedItems = [(AppDelegate *)[[UIApplication sharedApplication] delegate] selectedCategories];

    self.tableView.hidden = NO;

}

-(void) reloadMain {

    // countrySaved value from NSUserDefaults
    NSUserDefaults * defaults =  [NSUserDefaults standardUserDefaults];

    NSString *countryString = [defaults stringForKey:@"selectedCountryTableString"];
    NSString *cityString = [defaults stringForKey:@"selectedCityTableString"];
    NSLog(@"countrystring from category is %@", countryString);
    NSLog(@"citystring from category is %@", cityString);

    // getting path to the file

    if ([defaults stringForKey:@"selectedCountryTableString"] == NULL) {

        filePath = [[NSBundle mainBundle] pathForResource:@"categoriesit" ofType:@"json"];

    } else if ([countryString isEqualToString:@"UK"]) {

        filePath = [[NSBundle mainBundle] pathForResource:@"categoriesuk" ofType:@"json"];

    } else if ([countryString isEqualToString:@"Italy"]) {

        filePath = [[NSBundle mainBundle] pathForResource:@"categoriesit" ofType:@"json"];

    } else if ([countryString isEqualToString:@"Spain"]) {

        filePath = [[NSBundle mainBundle] pathForResource:@"categorieses" ofType:@"json"];

    } else if ([countryString isEqualToString:@"Brazil"]) {

        filePath = [[NSBundle mainBundle] pathForResource:@"categoriesbr" ofType:@"json"];
    }


    NSString *fileContent = [[NSString alloc] initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];

    //NSLog(@"File content: %@", fileContent);

    // creating new parser
    SBJSON *parser = [[SBJSON alloc] init];

    // parsing the first level
    NSDictionary *data = (NSDictionary *) [parser objectWithString:fileContent error:nil];
    NSDictionary *menu = (NSDictionary *) [data objectForKey:@"menu"];

#ifdef DEBUG
    NSLog(@"menu is %@",menu);
#endif

    NSMutableArray *itemsTMP = [[NSMutableArray alloc] init];

    NSData *jsonData = [NSData dataWithContentsOfFile:filePath];
    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:jsonData options:nil error:nil];

    // NSLog(@"results File test %@",dict);

    itemsTMP = [dict objectForKey:@"results"];
    // NSLog(@"itemsTMPitemsTMP File test %@",itemsTMP);

    self.arForTable = [itemsTMP copy];

    [self.tableView reloadData];

}

#pragma mark - Table view data source

- (int)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [self.arForTable count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];

        [cell.textLabel setFont:[UIFont fontWithName: @"Asap-Bold" size: 14.0f]];
        [cell.detailTextLabel setFont:[UIFont fontWithName: @"Asap-Bold" size: 14.0f]];

        cell.selectedBackgroundView = [[UIView alloc] initWithFrame:CGRectZero];

        cell.selectedBackgroundView.backgroundColor = [UIColor colorWithRed:204.0/255.0 green:56.0/255.0 blue:55.0/255.0 alpha:1];

    }

    UIImageView *cellAccessoryImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"icon-tick.png"]] ;
    UIImageView *cellAccessoryNoneImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@""]] ;


    if([_selectedItems containsObject:indexPath]){
        cell.accessoryView = cellAccessoryImageView;
    } else {
        cell.accessoryView = cellAccessoryNoneImageView;
    }

    // Get item from tableData
    NSDictionary *item = (NSDictionary *)[_arForTable objectAtIndex:indexPath.row];

    // encoding fix

    NSString *correctStringTitle = [NSString stringWithCString:[[item objectForKey:@"key"] cStringUsingEncoding:NSISOLatin1StringEncoding] encoding:NSUTF8StringEncoding];

    cell.textLabel.text = [correctStringTitle capitalizedString];

    NSNumber *num = [item objectForKey:@"id"];

    cell.detailTextLabel.text = [num stringValue];

    cell.detailTextLabel.hidden = YES;

    return cell;
}


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];

    NSUserDefaults * defaults =  [NSUserDefaults standardUserDefaults];

    if([_selectedItems containsObject:indexPath]){
        [_selectedItems removeObject:indexPath];

        [self.categorySelected removeObject:[[self.arForTable objectAtIndex:indexPath.row] objectForKey:@"id"]];

        string = [self.categorySelected componentsJoinedByString:@","];


        [defaults setObject:string forKey:@"selectedCategoryTableString"];

        NSLog(@"%@ defaults from did select remove categorySelected",[defaults stringForKey:@"selectedCategoryTableString"]);

        NSLog(@"%@ STRING FROM contains / removeObj",string);

    } else {

        [_selectedItems addObject:indexPath];

        [self.categorySelected addObject:[[self.arForTable objectAtIndex:indexPath.row] objectForKey:@"id"]];

        NSUserDefaults * defaults =  [NSUserDefaults standardUserDefaults];

        string = [self.categorySelected componentsJoinedByString:@","];

        [defaults setObject:string forKey:@"selectedCategoryTableString"];

        NSLog(@"%@ providerSelected from did select add ",self.categorySelected);

        NSLog(@"%@ STRING FROM contains / addObj",string);

    }

    [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    //      [tableView reloadData];
}


-(void) viewWillAppear:(BOOL)animated {

    [super viewWillAppear:NO];

    [self.navigationController setNavigationBarHidden:YES animated:NO];

    self.navigationController.toolbarHidden = YES;

    NSUserDefaults * defaults =  [NSUserDefaults standardUserDefaults];

 //   NSLog(@"ALL DEFAULTS %@", [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]);

    NSLog(@"%@ defaults from view appear categorySelected",[defaults stringForKey:@"selectedCategoryTableString"]);

    string = [defaults stringForKey:@"selectedCategoryTableString"];


    NSLog(@"%@ STRING from will appear",string);

}
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

也在我在.h中的app委托:

@property (strong, nonatomic) NSMutableArray *selectedCategories;

和.m:

 `_selectedCategories = [NSMutableArray new];
didFinishLaunchingWithOptions:方法

中的

要明确:

当视图再次出现时(如果我输出nslog),mutablearray已保存并正确检索。只有再次触摸一个tablerow时,mutable数组才会自行清除。 谢谢,如果有人可以帮助这个。我已经坚持了一段时间......

5 个答案:

答案 0 :(得分:3)

每次用户访问其他视图并返回时 self.categorySelected = [[NSMutableArray alloc] init];被执行,导致它成为一个空数组。

答案 1 :(得分:3)

首先在离开视图时序列化数组:

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:@[@"1",@"2",@"3"]];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"myarray"];
[[NSUserDefaults standardUserDefaults] synchronize];

然后在返回该视图时反序列化它:

NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:@"myarray"];
NSArray *myarray = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSLog(@"MYARRAY %@", myarray);

注意:如果找不到密钥,则初始化一个新数组。

答案 2 :(得分:3)

修改

// DONT EVER EVER EVER EVER EVER EVER DO THIS!!!
//  We don't use types as variable names, that is implicit...
//  I get it, this is a string, BUT WHAT IS IT A STRING OF, the name
//  'string' does you, and anyone else, no good.  Think about all your 
//  code like you are writing it for someone else, because when you come
//  back to it in 6 months, you will be someone else, and you won't know
//  what this means
NSString *string;

结束修改

我不会以这种方式使用NSUserDefaults。您已经将JSON解析为可归档对象(NSMutableArray)。在viewDidLoad中,你应该尝试做类似的事情:

-(void)viewDidLoad
{
     // Load the array from a plist file
     self.dataYouNeed = [NSMutableArray arrayWithContentsOfFile:@"someFileName.plist"];
     // If we got back nil, that file didn't exist, so call 'reloadMain',
     //  do your parsing there THEN SAVE to a plist using:
     //
     // [myArray writeToFile:@"someFileName.plist"]
     //
     if(self.dataYouNeed == nil) [self reloadMain];

     // Then do the exact same thing when you try to persist your selection...
     //  aka do not store a CSV string, just store an Array, and call writeToFile:
     //  when you want to save, and arrayWithContentsOfFile when you want to read 
     //  it back in

}

最重要的是,根据数据的来源,我会将所有数据从JSON文件中移出并在plist中设置,然后你可以抛弃所有的解析代码.... :)。基本上我说这对于这么简单的任务来说太复杂了,让自己的生活变得更轻松。

修改

你可能遇到不使用'self.string'的问题,只是提到'string'是危险的,你每次都在创建一个新的引用。这很可能会造成内存泄漏。 (ARC不是魔术,它无法为您处理所有内存管理)

修改

好的,所以重新阅读你的代码,我注意到了一些事情。

1。为什么要将CSV字符串存储在'string'实例var?

这有点多余。如果没有在之前的几行代码中设置它,你从来没有读过这个变量。它应该只是在方法范围内声明的NSString。

2。您是否期望'_selectedItems'保留对AppDelegate上'selectedCategories'数组的引用?

你不能做出这个假设,特别是没有做出@property声明。 ARC不知道如何处理它,并且可能在您离开视图时释放引用。更有可能的是,每次设置该变量时都会产生内存泄漏。您也不能保证再次调用viewDidLoad来重置引用。您应该在viewWillAppear中设置它。

3。哪个NSMutableArray您遇到了<?h2>的nil引用

如果是'_selectedItems',请考虑#2。如果它是'categorySelected',当这个视图消失时,也可能会释放它。如果这确实是你想要坚持的,那你为什么不从viewDidAppear方法填充它。你在viewDidAppear中唯一做的就是设置'string'变量(从来没有真正读过它,比如#1所说)。你的意思是在这里设置'categorySelected'吗?我相信你的意思是从NSUserDefaults获取你的列表,然后使用该字符串的componentsSeparatedByString:方法填充'categorySelected',它返回一个数组

答案 3 :(得分:2)

你能尝试在这里将'保留'改为'强'吗?

@property (nonatomic, retain) NSMutableArray *categorySelected;

答案 4 :(得分:2)

我认为问题是,您在selectedItems方法中设置了viewDidLoad数组。可能viewDidLoad正在运作一次。

只需在viewWillAppear方法中添加以下行:

_selectedItems = [(AppDelegate *)[[UIApplication sharedApplication] delegate] selectedCategories];