UITableView中的单元格问题

时间:2012-05-11 01:44:53

标签: ios xcode uitableview pushviewcontroller

我正在写一个简单的清单应用程序。我有两个UIViewControllers。第一个在UITableView中显示清单。我正在使用UIBarButtonItem将第二个视图推送到堆栈以添加新任务。所有任务都保存在一个数组中。

除了一件事,一切都很好。

如果我进入编辑模式并从表格视图中删除一个项目,该项目将从表格视图和数组中删除 - 这部分似乎工作正常。但是,删除项目后,如果我点击栏按钮项目添加新任务,我就会遇到问题。

我的NSLog告诉我新项目已添加到数组中,但是当我返回到表视图时,已删除的项目显示而不是新项目。表视图似乎正在重用已出列的单元格(不确定)。

我做错了什么?

CLCheckListViewController.m

#import "CLCheckListViewController.h"
#import "CLTaskFactory.h"
#import "CLTaskStore.h"
#import "CLAddTaskViewController.h"

@implementation CLCheckListViewController
{
    __weak IBOutlet UITableView *checkList;
}

- (id)init
{
    self = [super init];
    if (self) {
        // add five sample tasks
        CLTaskFactory *task1 = [[CLTaskFactory alloc] init];
        [task1 setTaskName:@"Task 1"];
        [task1 setDidComplete:NO];
        [[CLTaskStore sharedStore] addTask:task1];

        CLTaskFactory *task2 = [[CLTaskFactory alloc] init];
        [task2 setTaskName:@"Task 2"];
        [task2 setDidComplete:NO];
        [[CLTaskStore sharedStore] addTask:task2];

        CLTaskFactory *task3 = [[CLTaskFactory alloc] init];
        [task3 setTaskName:@"Task 3"];
        [task3 setDidComplete:NO];
        [[CLTaskStore sharedStore] addTask:task3];

        CLTaskFactory *task4 = [[CLTaskFactory alloc] init];
        [task4 setTaskName:@"Task 4"];
        [task4 setDidComplete:NO];
        [[CLTaskStore sharedStore] addTask:task4];

        CLTaskFactory *task5 = [[CLTaskFactory alloc] init];
        [task5 setTaskName:@"Task 5"];
        [task5 setDidComplete:NO];
        [[CLTaskStore sharedStore] addTask:task5];
    }
    return self;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [checkList reloadData];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // create edit button
    [[self navigationItem] setLeftBarButtonItem:[self editButtonItem]];

    // create title
    [[self navigationItem] setTitle:@"Checklist"];

    // create add guest button
    UIBarButtonItem *bbi = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(pushAddTask)];
    [[self navigationItem] setRightBarButtonItem:bbi];
}

- (void)pushAddTask
{
    CLAddTaskViewController *advk = [[CLAddTaskViewController alloc] init];
    [[self navigationController] pushViewController:advk animated:YES];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [[[CLTaskStore sharedStore] allTasks] count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [checkList dequeueReusableCellWithIdentifier:CellIdentifier];

    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];

        // put the tasks into the cell
        [[cell textLabel] setText:[NSString stringWithFormat:@"%@", [[[CLTaskStore sharedStore] allTasks] objectAtIndex:[indexPath row]]]];

        // put the checkbox into the cell's accessory view
        UIButton *checkBox = [UIButton buttonWithType:UIButtonTypeCustom];
        checkBox = [UIButton buttonWithType:UIButtonTypeCustom];
        [checkBox setImage:[UIImage imageNamed:@"checkbox.png"] forState:UIControlStateNormal];
        [checkBox setImage:[UIImage imageNamed:@"checkbox-checked.png"] forState:UIControlStateSelected];
        checkBox.frame = CGRectMake(0, 0, 30, 30);
        checkBox.userInteractionEnabled = YES;
        [checkBox addTarget:self action:@selector(didCheckTask:) forControlEvents:UIControlEventTouchDown];
        cell.accessoryView = checkBox;
    }
    return cell;
}

- (void)didCheckTask:(UIButton *)button
{
    CGPoint hitPoint = [button convertPoint:CGPointZero toView:checkList];
    hitIndex = [checkList indexPathForRowAtPoint:hitPoint];

    task = [[[CLTaskStore sharedStore] allTasks] objectAtIndex:[hitIndex row]];

    if (task.didComplete) {
        task.didComplete = NO;
    } else {
        task.didComplete = YES;
    }

    NSInteger taskCount = [[[CLTaskStore sharedStore] allTasks] count];
    for (int i = 0; i < taskCount; i++) {
        NSLog(@"%@, status: %@", [[[CLTaskStore sharedStore] allTasks] objectAtIndex:i], [[[[CLTaskStore sharedStore] allTasks] objectAtIndex:i] didComplete]?@"YES":@"NO");
    }

    // toggle checkbox
    button.selected = !button.selected;
}

- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
    [super setEditing:editing animated:animated];

    // set editing mode
    if (editing) {
        self.navigationItem.title = @"Edit Checklist";
        [checkList setEditing:YES];
    } else {
        self.navigationItem.title = @"Checklist";
        [checkList setEditing:NO];
    }
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
                                            forRowAtIndexPath:(NSIndexPath *)indexPath
{
    // remove task
    if (editingStyle == UITableViewCellEditingStyleDelete) {

        // remove task from CLTaskStore
        task = [[[CLTaskStore sharedStore] allTasks] objectAtIndex:[indexPath row]];
        [[CLTaskStore sharedStore] removeTask:task];

        // remove guest from table view
        [checkList deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];

        // reload table view
        //[checkList reloadData];
    }
}

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
    [[CLTaskStore sharedStore] moveTaskAtIndex:[sourceIndexPath row] toIndex:[destinationIndexPath row]];
}

@end

CLAddTaskViewController.m

#import "CLAddTaskViewController.h"
#import "CLTaskFactory.h"
#import "CLTaskStore.h"

@implementation CLAddTaskViewController

    - (void)viewDidLoad
    {
        [[self navigationItem] setTitle:@"Add Task"];
    }

    - (void)viewWillDisappear:(BOOL)animated
    {
        [super viewWillDisappear:animated];

        // clear first responder
        [[self view] endEditing:YES];

        // create new task
        CLTaskFactory *newTask = [[CLTaskFactory alloc] init];
        [newTask setTaskName:[newTaskName text]];

        // add new guest to RCGuestStore
        [[CLTaskStore sharedStore] addTask:newTask];
    }

    @end

CLAddTaskFactory.m

#import "CLTaskFactory.h"

@implementation CLTaskFactory

@synthesize taskName;

- (void)setDidComplete:(BOOL)dc
{
    didComplete = dc;
}

- (BOOL)didComplete
{
    return didComplete;
}

- (NSString *)description
{
    // override the description
    NSString *descriptionString = [[NSString alloc] initWithFormat:@"%@", taskName];
    return descriptionString;
}

@end

CLAddTaskStore.m

#import "CLTaskStore.h"
#import "CLTaskFactory.h"
#import "CLCheckListViewController.h"

@implementation CLTaskStore

+ (id)allocWithZone:(NSZone *)zone
{
    return [self sharedStore];
}

+ (CLTaskStore *)sharedStore
{
    static CLTaskStore *sharedStore = nil;
    if (!sharedStore) {
        sharedStore = [[super allocWithZone:nil] init];
    }
    return sharedStore;
}

- (id)init
{
    self = [super init];
    if (self) {
        allTasks = [[NSMutableArray alloc] init];
    }
    return self;
}

- (NSMutableArray *)allTasks
{
    return allTasks;
}

- (void)addTask:(CLTaskFactory *)task
{
    [allTasks addObject:task];
    NSLog(@"Task added: %@", task);
}

- (void)removeTask:(CLTaskFactory *)task
{
    // remove the item for the deleted row from the store
    [allTasks removeObjectIdenticalTo:task];

    NSInteger taskCount = [allTasks count];
    NSLog(@"Removed: %@, there are now %d remaining tasks, they are:", task, taskCount);
    for (int i = 0; i < taskCount; i++) {
        NSLog(@"%@, status: %@", [[[CLTaskStore sharedStore] allTasks] objectAtIndex:i], [[[[CLTaskStore sharedStore] allTasks] objectAtIndex:i] didComplete]?@"YES":@"NO");
    }
}

- (void)moveTaskAtIndex:(int)from toIndex:(int)to
{
    if (from == to) {
        return;
    }

    CLTaskFactory *task = [allTasks objectAtIndex:from];
    [allTasks removeObjectAtIndex:from];
    [allTasks insertObject:task atIndex:to];
}

@end

感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

  

表视图似乎正在重用出列的单元格

这正是它的作用;尽可能重用细胞。如果你有足够的项目来导致表视图滚动,你也会看到同样的问题。

-tableView:cellForRowAtIndexPath:中,您必须始终设置单元格以显示给定行索引的正确内容,无论dequeueReusableCellWithIdentifier:是否返回单元格。

基本上:

  • 如果-dequeueReusableCellWithIdentifier:返回nil,请创建一个新单元格并添加复选框按钮。

  • 然后在此新单元格或从-dequeueReusableCellWithIdentifier:

  • 返回的单元格上设置单元格文本和按钮状态

答案 1 :(得分:1)

达伦是对的。如果你在这里查看你的代码:

if (!cell) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];

    // put the tasks into the cell
    [[cell textLabel] setText:[NSString stringWithFormat:@"%@", [[[CLTaskStore sharedStore] allTasks] objectAtIndex:[indexPath row]]]];

    // put the checkbox into the cell's accessory view
    UIButton *checkBox = [UIButton buttonWithType:UIButtonTypeCustom];
    checkBox = [UIButton buttonWithType:UIButtonTypeCustom];
    [checkBox setImage:[UIImage imageNamed:@"checkbox.png"] forState:UIControlStateNormal];
    [checkBox setImage:[UIImage imageNamed:@"checkbox-checked.png"] forState:UIControlStateSelected];
    checkBox.frame = CGRectMake(0, 0, 30, 30);
    checkBox.userInteractionEnabled = YES;
    [checkBox addTarget:self action:@selector(didCheckTask:) forControlEvents:UIControlEventTouchDown];
    cell.accessoryView = checkBox;
}

您唯一设置单元格if(cell == nil) 将您的代码更改为

if (!cell) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// put the tasks into the cell
[[cell textLabel] setText:[NSString stringWithFormat:@"%@", [[[CLTaskStore sharedStore] allTasks] objectAtIndex:[indexPath row]]]];

// put the checkbox into the cell's accessory view
UIButton *checkBox = [UIButton buttonWithType:UIButtonTypeCustom];
checkBox = [UIButton buttonWithType:UIButtonTypeCustom];
[checkBox setImage:[UIImage imageNamed:@"checkbox.png"] forState:UIControlStateNormal];
[checkBox setImage:[UIImage imageNamed:@"checkbox-checked.png"] forState:UIControlStateSelected];
checkBox.frame = CGRectMake(0, 0, 30, 30);
checkBox.userInteractionEnabled = YES;
[checkBox addTarget:self action:@selector(didCheckTask:) forControlEvents:UIControlEventTouchDown];
cell.accessoryView = checkBox;