在 NSUserDefaults 中保存复选标记 - 动态 TableView

Posted

技术标签:

【中文标题】在 NSUserDefaults 中保存复选标记 - 动态 TableView【英文标题】:Save checkmark in NSUserDefaults - dynamic TableView 【发布时间】:2015-01-05 23:47:10 【问题描述】:

解决方案!!

感谢乔希的耐心:D

因此,初始问题中的代码始终勾选所选单元格并取消选择先前选择的单元格,而不将任何内容保存到NSUserDefaults。在 Josh 的大量帮助之后,新代码(右下方)如下(与他的回复中完全相同/我只是稍微整理了一下,并删除了之前尝试使其正常工作中定义的 @properties)。

用户点击 7 个单元格之一。然后将点击单元格的 indexPath 保存在NSUserdefaults 中,当再次打开 TableView 时,会在先前点击的单元格旁边显示一个复选标记。索引路径始终保存在同一个NSObject中,因此只会显示一个复选标记。

#import "CycleTableViewController.h"
#import "SettingsTableViewController.h"

@interface CycleTableViewController ()
@property (nonatomic) int selectedRow;
@end

@implementation CycleTableViewController
@synthesize array;

- (void)viewDidLoad 
    //load array containing options
    array=@[@"1", @"2",  @"3", @"4", @"5", @"6", @"7"];

    [super viewDidLoad];
    

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

- (void) viewWillDisappear:(BOOL)animated
    //save indexpath of tapped cell to NSUserdefaults
    [[NSUserDefaults standardUserDefaults] setObject:@(indexPath.row) forKey:@"cycle"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
    return 1;
    

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
    return [array count];
    

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    static NSString *CellIndentifier=@"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIndentifier forIndexPath:indexPath];

    cell.textLabel.text = [array objectAtIndex:indexPath.row];
   
    //display checkmark next to the tapped cell
    if(indexPath.row == self.selectedRow)
       cell.accessoryType = UITableViewCellAccessoryCheckmark;
        
    else
       ell.accessoryType = UITableViewCellAccessoryNone;
                 
        return cell;
    

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
    //assign indexpath to selectedRow, so NSUserdefaults can save them
    self.selectedRow = indexPath.row;        
    [self.tableView reloadData];
    

    //save indexpath of tapped cell to NSUserdefaults
    [[NSUserDefaults standardUserDefaults] setObject:@(indexPath.row) forKey:@"cycle"];
    [[NSUserDefaults standardUserDefaults] synchronize];

@end

初始问题

我在这里阅读了大量关于将索引路径保存为用户默认值的帖子,但没有一个对我有用...

在下面的 TableView 中,我有一个数据数组 (1-7),一旦按下单元格,就会显示并传递给另一个 ViewController。按下的单元格有一个复选标记,如果我使用导航控制器返回,我可以看到复选标记。一次只选择一项。如果我按另一行,复选标记会更改。

所以现在我想将所选行的索引路径保存到 UserDefaults(在 didselectrowat indexpath 中)并将其加载到 viewdidload 但我总是得到一个 build failed,无论我尝试什么......

有人可以指出我正确的方向吗?这应该很容易,但不知何故我无法让它工作:/

更新代码!一旦我得到它的工作,我会上传完成的答案!

#import "CycleTableViewController.h"
#import "SettingsTableViewController.h"


@interface CycleTableViewController ()
    NSString *currentCategory; // pointer to the currently checked item

// other @property declarations here or in your .m file
#define CHECKED_KEY @"kCheckedBoxKey"

@property (nonatomic) int selectedRow;



@end

@implementation CycleTableViewController
@synthesize array;



- (void)viewDidLoad 
    
    //load tickmark according to newCell;
    
    array=@[@"21+7", @"22+6",  @"23+5", @"24+4", @"25+3", @"26+2", @"28"];

    [super viewDidLoad];


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

-(void) viewWillAppear:(BOOL)animated 
    self.selectedRow = [[[NSUserDefaults standardUserDefaults] objectForKey:@"cycle"] intValue];
    
 

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
    return 1;


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
    return [array count];


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    static NSString *CellIndentifier=@"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIndentifier forIndexPath:indexPath];
    
    cell.textLabel.text = [array objectAtIndex:indexPath.row];
    
    return cell;



- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
    
    [[NSUserDefaults standardUserDefaults] setObject:@(indexPath.row) forKey:@"cycle"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    
    NSIndexPath *IndexPath = [NSIndexPath indexPathForRow:self.selectedRow inSection:0];
    UITableViewCell *Cell = [tableView cellForRowAtIndexPath:IndexPath];
    Cell.accessoryType = UITableViewCellAccessoryCheckmark;
    


@end

【问题讨论】:

【参考方案1】:
#import "CycleTableViewController.h"
#import "SettingsTableViewController.h"


@interface CycleTableViewController ()
    NSString *currentCategory; // pointer to the currently checked item

// other @property declarations here or in your .m file
#define CHECKED_KEY @"kCheckedBoxKey"

@property (nonatomic) int selectedRow;

@end

@implementation CycleTableViewController
@synthesize array;

- (void)viewDidLoad 

    //load tickmark according to newCell;

    array=@[@"21+7", @"22+6",  @"23+5", @"24+4", @"25+3", @"26+2", @"28"];

    [super viewDidLoad];


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


- (void) viewWillAppear:(BOOL)animated 
    self.selectedRow = [[[NSUserDefaults standardUserDefaults] objectForKey:@"cycle"] intValue];        
 

- (void) viewWillDisappear:(BOOL)animated
    [[NSUserDefaults standardUserDefaults] setObject:@(indexPath.row) forKey:@"cycle"];
    [[NSUserDefaults standardUserDefaults] synchronize];


#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
    return 1;


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
    return [array count];


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    static NSString *CellIndentifier=@"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIndentifier forIndexPath:indexPath];

    cell.textLabel.text = [array objectAtIndex:indexPath.row];

    if(indexPath.row == self.selectedRow)
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
     
    else
        cell.accessoryType = UITableViewCellAccessoryNone;
             
    return cell;


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
     self.selectedRow = indexPath.row;        
     [self.tableView reloadData];


@end

【讨论】:

感谢乔希的耐心和巨大的帮助!它终于起作用了,您的逻辑显然是正确的。我也一直在引用 self.tableview 来加载数据...再次非常感谢,当我达到 15 分时,我会宣布您的答案并竖起大拇指:) 还不能这样做.. .【参考方案2】:

您在代码中的哪个位置保存用户默认值?

didSelectRowAtIndexPath,你可以添加:

[[NSUserDefaults standardUserDefaults] setObject:@(indexPath.row) forKey:@"nameOfSetting"];
[[NSUserDefaults standardUserDefaults] synchronize];

cellForRowAtIndexPath你可以检查是否

indexPath.row == [[[NSUserDefaults standardUserDefaults] objectForKey:@"nameOfSetting"] intValue]

如果是这样,请添加复选标记附件。如果不是,则不显示任何附件。

请注意,我实际上会创建一个包含 selectedValue 的属性,并且只有在离开设置页面或点击保存按钮时,您才会真正更新用户默认值。然后在viewWillAppear 中,我将此属性设置为等于用户默认值中的设置,并在表上调用 reload。

编辑 要扩展最后的注释,您可以执行以下操作:

在界面中...

@property (nonatomic) int selectedRow;

在实现中...

self.selectedRow = [[NSUserDefaults standardUserDefaults] objectForKey:@"nameOfsetting"] intValue];

只要在头文件中声明了 selectedRow 属性,您就可以将此代码放在您要从中分离的上一个视图控制器中的 viewWillAppearviewDidAppear 甚至 prepareForSegue 中。我不会把这段代码放在viewDidLoad

然后分别在cellForRowAtIndexPath 中添加类似的内容:

if(indexPath.row == self.selectedRow)
    cell.accessoryType = UITableViewCellAccessoryCheckmark;

else
    cell.accessoryType = UITableViewCellAccessoryNone;

编辑#2

在显示当前设置的OptionsViewController 中,您可以从standardUserDefaults 加载设置。您可以像我提到的那样保存一个数字作为设置(即,如果您有设置选项,您可以将它们编号为 0 - 6 并使用 typedef 使代码更清晰),或者您可以存储一个字符串。如果您将设置存储为数字,则只需要字典将数字映射到设置描述。如果您将设置存储为字符串,则可以只显示该字符串。

无论选择哪种方法,在OptionsViewController 中执行以下操作:

#import "SettingsViewController.h"

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
   if([segue.destinationViewController isKindOfClass:[SettingsViewController class]])
       SettingsViewController *settingsViewController = (SettingsViewController *) segue.destinationViewController;
       settingsViewController.selectedSetting= <INSERT YOUR SETTING FROM STANDARDUSERDEFAULTS>
    
 

基本上,您将设置从选项传递到包含您的表格的设置视图。您可以将selectedSetting 中的SettingsViewController 设为上面的数字或字符串。同样,您必须将设置转换为数字,以便表格知道哪一行有复选标记。我会保持其余代码相同,即cellForRowAtIndexPath 中的 if 语句。您需要以某种方式检查 indexPath.row 是否与 selectedSetting 匹配(即,如果它是字符串,则需要将其转换为数字)。并在viewWillAppearviewDidAppear 中重新加载tableView,以便显示复选标记。

当用户选择不同的行时,您可以更新 selectedSetting 属性,然后在 viewWillDisappearprepareForSegue(即在展开转场之前)您可以更新 standardUserDefaults。

【讨论】:

感谢您的快速回复,乔希!你粘贴在那里的实际上是我一直在做的。但是,如果我将第一个复制到didselectrowatindexpath 以保存索引路径,并将第二个复制到“viewdidload”以加载复选标记,我总是会遇到未声明的标识符问题。我觉得这是我忽略的超级简单的事情:/ 你会在cellForRowAtIndexviewdidload 中加载路径吗?你会怎么把它放在那里?关于您的最后一条评论:我遗漏了一个自动显示另一个视图控制器的 segue。 哪行代码给你未声明的标识符错误?没有声明的具体方法是什么? 非常感谢您的广泛回复。不幸的是,我认为我没有很好地表达我的问题。我有一个设置页面,它打开包含 7 个选项的 TableView,代码在被点击时勾选选定的行,然后关闭 TableViewController 并通过 segue 将 indexpath 转发到显示它的选项页面。我想保存那个刻度线(cellForRowAtIndexPath 中的 NSuserdefault),当我再次打开 tableview 时自动加载它(例如从 viewdidlod 中),这样刻度线就会显示出来。您的代码只检查点击的单元格是否等于保存的行,不是吗? 我添加了第二个编辑 :)。整个过程是让 OptionsViewController 每次出现时都从 standardUserDefaults 加载,当它与 SettingsViewController 连接时将当前设置移交给 SettingsViewController,显示对应于该特定设置的行的复选标记,当设置发生更改时更新 standardUserDefaults,然后再展开回选项视图控制器。当 OptionsViweController 再次出现时,它将从 standardUserDefaults 重新加载并显示更新的设置。 哈哈乔希我想我在这里测试你的耐心...... :O 所以我将索引路径保存在NSuserdefaultson 选择中并将它们加载到选项视图控制器中。这工作正常。我仍然留下标记。我只需要代码来始终选择self.selectedRow 处的单元格。我在didselectrow上面做了什么不应该这样做吗?但这并没有打勾:/

以上是关于在 NSUserDefaults 中保存复选标记 - 动态 TableView的主要内容,如果未能解决你的问题,请参考以下文章

设置静态表格视图单元格的复选标记

复选框保存/加载NSUserdefaults

如何在uitableViewCell中保存UIButton的状态?

如何在 Swift 中保存复选标记?

在 Swift 中保存 UITableViewCell 复选标记选择

使用 NSUserDefaults 和 AVAudioPlayer 制作静音切换按钮