-1

我有一个 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中的应用程序委托中:

@property (strong, nonatomic) NSMutableArray *selectedCategories;

在 .m 中:

 `_selectedCategories = [NSMutableArray new];

didFinishLaunchingWithOptions:方法中

只是要清楚:

当视图再次出现时(如果我 nslog 输出),mutablearray 已被保存并被正确检索。可变数组仅在再次触摸 tablerow 时自行清除。感谢是否有人可以提供帮助。我已经坚持了一段时间了...

4

5 回答 5

3

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

于 2013-02-21T14:11:08.517 回答
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);

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

于 2013-02-25T01:56:44.080 回答
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 字符串存储在“字符串”实例变量中?

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

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

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

3. 你遇到的是哪个 NSMutableArray 的 nil 引用?

If it is '_selectedItems', consider #2. If it is 'categorySelected', this is also probably being released when this view disappears. If this is really what you are trying to persist, then why are you not populating it from the viewDidAppear method. The only thing you do in viewDidAppear is set the 'string' variable (which is never actually read from, like #1 says). Did you mean to set 'categorySelected' here? I believe you meant to get your list from NSUserDefaults, then populate 'categorySelected' using that string's componentsSeparatedByString: method, which returns an array

于 2013-02-25T21:52:56.720 回答
2

您可以尝试在这里将“保留”更改为“强”吗?

@property (nonatomic, retain) NSMutableArray *categorySelected;
于 2013-02-21T14:11:57.907 回答
2

I think the issue is, you are setting the selectedItems array in viewDidLoad method. Probably the viewDidLoad is working once.

Just add the following line in your viewWillAppear method:

_selectedItems = [(AppDelegate *)[[UIApplication sharedApplication] delegate] selectedCategories];
于 2013-03-01T12:14:25.750 回答