我有一个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数组才会自行清除。 谢谢,如果有人可以帮助这个。我已经坚持了一段时间......
答案 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不是魔术,它无法为您处理所有内存管理)
修改强>
好的,所以重新阅读你的代码,我注意到了一些事情。
这有点多余。如果没有在之前的几行代码中设置它,你从来没有读过这个变量。它应该只是在方法范围内声明的NSString。
你不能做出这个假设,特别是没有做出@property声明。 ARC不知道如何处理它,并且可能在您离开视图时释放引用。更有可能的是,每次设置该变量时都会产生内存泄漏。您也不能保证再次调用viewDidLoad来重置引用。您应该在viewWillAppear中设置它。
如果是'_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];