iOS-[UITableView重新加载数据]重新加载,但不删除旧单元格?

iOS-[UITableView重新加载数据]重新加载,但不删除旧单元格?,ios,uitableview,reloaddata,Ios,Uitableview,Reloaddata,这很奇怪,我知道,但我的[UITableView reloadData]没有删除旧单元格,如下所示: 您看到的混乱发生在我单击+按钮后,返回并再次更改值。plus按钮将navigationController推到另一个控制器上,当我点击返回按钮并更改值后,我看到的就是这个。这怎么可能??我使用了一个自定义视图(从UIView子类化),我创建了一个带有UILabel的UIStepper。以下是自定义UIView的代码、controller.m和.h-.m文件 控制器.m @interface V

这很奇怪,我知道,但我的[UITableView reloadData]没有删除旧单元格,如下所示:

您看到的混乱发生在我单击+按钮后,返回并再次更改值。plus按钮将navigationController推到另一个控制器上,当我点击返回按钮并更改值后,我看到的就是这个。这怎么可能??我使用了一个自定义视图(从UIView子类化),我创建了一个带有UILabel的UIStepper。以下是自定义UIView的代码、controller.m和.h-.m文件

控制器.m

@interface ViewController ()
@property NSString *docsDir;
@property sqlite3 *DB;
@property NSArray *dirPaths;
@property NSString* databasePath;
@property (strong, nonatomic) IBOutlet UITableView *tableView;
@property BOOL isCreatedBefore;
@property NSArray *theList;
@end

@implementation ViewController
@synthesize docsDir;
@synthesize DB;
@synthesize dirPaths;
@synthesize databasePath;
- (void)viewDidLoad
{
    [super viewDidLoad];
    dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    docsDir = [dirPaths objectAtIndex:0];
    databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: [NSString stringWithFormat:@"database.db"]]];

    [self createDatabase];
    self.theList = [self readAllEntries];
}

-(void) viewWillAppear:(BOOL)animated{
    self.theList = [self readAllEntries];
    [self.tableView reloadData];
}

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

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{   SeriesObject * obj = [self.theList objectAtIndex:indexPath.row];
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellocan"];
    UILabel *nameLabel = (UILabel *)[cell.contentView viewWithTag:1];
    [nameLabel setText:obj.name];

    CounterView *seasonCounter = [[CounterView alloc] initWithX:220 WithY:28 WithName:obj.name withCount:obj.session withCustomTag:indexPath.row];
    seasonCounter.tag = 2;
    CounterView *episodeCounter = [[CounterView alloc] initWithX:268 WithY:28 WithName:obj.name withCount:obj.episode withCustomTag:indexPath.row];
    episodeCounter.tag = 4;

    [cell.contentView addSubview:seasonCounter];
    [cell.contentView addSubview:episodeCounter];

    return cell;
}


- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    // Return YES if you want the specified item to be editable.
    return YES;
}

// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        SeriesObject *obj = [self.theList objectAtIndex:indexPath.row];
        [self deleteEntryWithID:obj.idd];

        self.theList = [self readAllEntries];
        [self.tableView reloadData];
    }
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return 88;
}



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

}

______and more about reading from database or deleting; not about the view. (this is a very simple app, as a free time hobby; so I didn't spend time to follow MVC)
@interface CounterView()

@property NSString *docsDir;
@property sqlite3 *DB;
@property NSArray *dirPaths;
@property NSString* databasePath;

@end


@implementation CounterView

@synthesize docsDir;
@synthesize DB;
@synthesize dirPaths;
@synthesize databasePath;

- (id)initWithX:(CGFloat)xPoint WithY:(CGFloat)yPoint WithName:(NSString*)newName withCount:(NSInteger)newCount withCustomTag:(NSInteger)newTag
{
    self = [super initWithFrame:CGRectMake(xPoint, yPoint, 24, 52)];
    if (self) {
        self.customTag = newTag;
        self.count = newCount;
        self.name = newName;

        UIButton *btnUp = [[UIButton alloc] initWithFrame:CGRectMake(3, 2, 18, 12)];
        [btnUp setImage:[UIImage imageNamed:@"top.png"] forState:UIControlStateNormal];
        [btnUp addTarget:self action:@selector(increaseValue) forControlEvents:UIControlEventTouchUpInside];
        UIButton *btnDown = [[UIButton alloc] initWithFrame:CGRectMake(3, 38, 18, 12)];
        [btnDown setImage:[UIImage imageNamed:@"bottom.png"] forState:UIControlStateNormal];
        [btnDown addTarget:self action:@selector(decreaseValue) forControlEvents:UIControlEventTouchUpInside];
        self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 14, 24, 24)];
        [self.label setText:[NSString stringWithFormat:@"%ld", (long)self.count]];
        self.label.textAlignment = NSTextAlignmentCenter;

        [self addSubview:btnUp];
        [self addSubview:btnDown];
        [self addSubview:self.label];
    }
    return self;
}

- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents{

}


-(void) increaseValue{
    self.count++;
    [self.label setText:[NSString stringWithFormat:@"%ld", (long)self.count]];
}
-(void) decreaseValue{
    self.count--;
    [self.label setText:[NSString stringWithFormat:@"%ld", (long)self.count]];
}

____and some more database codes too..
反视图.h

@interface CounterView : UIView
@property NSString* name;
@property NSInteger count;
@property UILabel *label;
@property NSInteger customTag;

- (id)initWithX:(CGFloat)xPoint WithY:(CGFloat)yPoint WithName:(NSString*)newName withCount:(NSInteger)newCount withCustomTag:(NSInteger)newTag;
@end
CounterView.m

@interface ViewController ()
@property NSString *docsDir;
@property sqlite3 *DB;
@property NSArray *dirPaths;
@property NSString* databasePath;
@property (strong, nonatomic) IBOutlet UITableView *tableView;
@property BOOL isCreatedBefore;
@property NSArray *theList;
@end

@implementation ViewController
@synthesize docsDir;
@synthesize DB;
@synthesize dirPaths;
@synthesize databasePath;
- (void)viewDidLoad
{
    [super viewDidLoad];
    dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    docsDir = [dirPaths objectAtIndex:0];
    databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: [NSString stringWithFormat:@"database.db"]]];

    [self createDatabase];
    self.theList = [self readAllEntries];
}

-(void) viewWillAppear:(BOOL)animated{
    self.theList = [self readAllEntries];
    [self.tableView reloadData];
}

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

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{   SeriesObject * obj = [self.theList objectAtIndex:indexPath.row];
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellocan"];
    UILabel *nameLabel = (UILabel *)[cell.contentView viewWithTag:1];
    [nameLabel setText:obj.name];

    CounterView *seasonCounter = [[CounterView alloc] initWithX:220 WithY:28 WithName:obj.name withCount:obj.session withCustomTag:indexPath.row];
    seasonCounter.tag = 2;
    CounterView *episodeCounter = [[CounterView alloc] initWithX:268 WithY:28 WithName:obj.name withCount:obj.episode withCustomTag:indexPath.row];
    episodeCounter.tag = 4;

    [cell.contentView addSubview:seasonCounter];
    [cell.contentView addSubview:episodeCounter];

    return cell;
}


- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    // Return YES if you want the specified item to be editable.
    return YES;
}

// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        SeriesObject *obj = [self.theList objectAtIndex:indexPath.row];
        [self deleteEntryWithID:obj.idd];

        self.theList = [self readAllEntries];
        [self.tableView reloadData];
    }
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return 88;
}



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

}

______and more about reading from database or deleting; not about the view. (this is a very simple app, as a free time hobby; so I didn't spend time to follow MVC)
@interface CounterView()

@property NSString *docsDir;
@property sqlite3 *DB;
@property NSArray *dirPaths;
@property NSString* databasePath;

@end


@implementation CounterView

@synthesize docsDir;
@synthesize DB;
@synthesize dirPaths;
@synthesize databasePath;

- (id)initWithX:(CGFloat)xPoint WithY:(CGFloat)yPoint WithName:(NSString*)newName withCount:(NSInteger)newCount withCustomTag:(NSInteger)newTag
{
    self = [super initWithFrame:CGRectMake(xPoint, yPoint, 24, 52)];
    if (self) {
        self.customTag = newTag;
        self.count = newCount;
        self.name = newName;

        UIButton *btnUp = [[UIButton alloc] initWithFrame:CGRectMake(3, 2, 18, 12)];
        [btnUp setImage:[UIImage imageNamed:@"top.png"] forState:UIControlStateNormal];
        [btnUp addTarget:self action:@selector(increaseValue) forControlEvents:UIControlEventTouchUpInside];
        UIButton *btnDown = [[UIButton alloc] initWithFrame:CGRectMake(3, 38, 18, 12)];
        [btnDown setImage:[UIImage imageNamed:@"bottom.png"] forState:UIControlStateNormal];
        [btnDown addTarget:self action:@selector(decreaseValue) forControlEvents:UIControlEventTouchUpInside];
        self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 14, 24, 24)];
        [self.label setText:[NSString stringWithFormat:@"%ld", (long)self.count]];
        self.label.textAlignment = NSTextAlignmentCenter;

        [self addSubview:btnUp];
        [self addSubview:btnDown];
        [self addSubview:self.label];
    }
    return self;
}

- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents{

}


-(void) increaseValue{
    self.count++;
    [self.label setText:[NSString stringWithFormat:@"%ld", (long)self.count]];
}
-(void) decreaseValue{
    self.count--;
    [self.label setText:[NSString stringWithFormat:@"%ld", (long)self.count]];
}

____and some more database codes too..

cellforrowatinexpath:
中,每次都要添加一个子视图。UITableView会重复使用单元格,因此重新加载时会得到一个“脏”单元格。您需要检查视图是否已经存在。如果是,请修改视图,而不是添加视图。Google“UITableViewCell viewWithTag”查看一些示例代码。

我建议您创建一个从UITableViewCell派生的自定义单元格类,并让它包含自定义计数器视图实例。在这种情况下,您不必每次都在
CellForRowatineXpath
中添加子视图(这导致了您遇到的问题),而是可以传递它所需的任何值。

经过一些修改后,在CellForRowatineXpath:方法中使用此方法解决了所有问题。谢谢大家

- (void)prepareForReuse
{
    //remove your subviews here 
    [self.subViewToRemove removeFromSuperView];
}
if (cell != nil)
    {
        NSArray* subviews = [cell.contentView subviews];
        for (UIView* view in subviews)
        {
            [view removeFromSuperview];
        }
    }

我以前用过。所以每次都会发生,但由于内容稳定,我从未意识到。谢谢。@Esq这个模式已经被写了几百次了,很容易找到。这会在必要的时候起作用,但是如果你的细胞变得复杂,这种方法会让你的滚动感觉不稳定。重用视图比删除和添加视图更快。