【问题标题】:Reload TableView data after click button单击按钮后重新加载 TableView 数据
【发布时间】:2012-04-07 06:06:07
【问题描述】:

我正在制作聊天应用程序并从 SQLite 数据库读取消息数据。单击“发送”按钮后,我想用新消息重新加载 TableView 数据。 我的按钮的事件:

    [_sendButton addTarget:self action:@selector(saveMessage:) forControlEvents:UIControlEventTouchUpInside];

我想我需要使用-(void)viewDidAppear:(BOOL)animated,但它不起作用(或者我做错了什么)。

[_tableView reloadData];

-(void)viewDidAppear:(BOOL)animated {

sqlite3 *database;

databaseName = @"Messenges.db";
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:databaseName];

messenges = [[NSMutableArray alloc] init];

if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
    const char *sqlStatement = "select * from messenges";
    sqlite3_stmt *compiledStatement;
    if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
        while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
            NSString *dbMessageText = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];

            Message *messege = [[Message alloc] initWithName:dbMessageText];

            [messenges addObject:messege];

            [messege release];
        }
    }
    sqlite3_finalize(compiledStatement);

}
sqlite3_close(database);}

编辑 这是我向 TableView 添加新行的方法。单击“发送”按钮后必须立即添加新行。

-(IBAction)insertRows:(id)sender {
    MDAppDelegate *appDelegate = (MDAppDelegate *)[[UIApplication sharedApplication] delegate];
    [messenges insertObject:[[NSString alloc] initWithFormat:@"%@", _textField.text] atIndex:appDelegate.messenges.count+1];
    NSArray *insertIndexPaths = [NSArray arrayWithObject: [NSIndexPath indexPathForRow:1 inSection:1]];
    UITableView *tV = (UITableView *)self.tableView;

    [tV beginUpdates];
    [tV insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationRight];
    [tV endUpdates];}

但是这段代码给了我错误:'Invalid table view update. The application has requested an update to the table view that is inconsistent with the state provided by the data source.' 我该如何解决?

编辑2

好的。我只有 1 个部分。 numberOfSectionsInTableView: 不需要更正。

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    MDAppDelegate *appDelegate = (MDAppDelegate *)[[UIApplication sharedApplication] delegate];
    NSUInteger numberOfRowsInSection = appDelegate.messenges.count; //add new variable to what rows will be +1
    if (self.editing) {
        numberOfRowsInSection++;
    }
    return numberOfRowsInSection;}

但我仍然有同样的错误。

编辑#3

让我们看看。我将insertRows 更改为:

-(IBAction)insertRows:(id)sender {
    MDAppDelegate *appDelegate = (MDAppDelegate *)[[UIApplication sharedApplication] delegate];
    [self.tableView beginUpdates];
    self.tableView.editing = YES;
    [messenges insertObject:[[NSString alloc] initWithFormat:@"%@", _textField.text] atIndex:appDelegate.messenges.count+1];

    NSArray *insertIndexPaths = [NSArray arrayWithObject: [NSIndexPath indexPathForRow:appDelegate.messenges.count+1 inSection:1]];
    [self.tableView insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationRight];
    [self.tableView endUpdates];
}  

还有numberOfRowsInSection:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    MDAppDelegate *appDelegate = (MDAppDelegate *)[[UIApplication sharedApplication] delegate];
    NSUInteger numberOfRowsInSection = appDelegate.messenges.count;
    if (self.tableView.editing) {
           numberOfRowsInSection++;
    }
    NSLog(@"%i",numberOfRowsInSection);
    return numberOfRowsInSection;
}

但我收到了一个错误 *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 4 beyond bounds [0 .. 3]' 。然后我将if (self.tableView.editing) 更正为:

if (self.tableView.editing) {
    MDAppDelegate *someNewDelegate = (MDAppDelegate *)[[UIApplication sharedApplication] delegate];
    numberOfRowsInSection = someNewDelegate.messenges.count+1; //or .count
}

但是遇到了关于“NSRangeException”的相同错误。

【问题讨论】:

  • 查看Animate the insertion of a new section in UITableVIew。它还讨论了在现有部分中以动画方式插入行。
  • 我只是想指出,您拼写了我认为应该是 message 的内容,三种不同的方式:message、messenge 和 messege。我认为只有其中一个是正确的。如果这些应该是四个不同的词,我认为你需要一个不同的命名方案。
  • @Sam 我对您的链接有一个问题。这些方法有能力在点击“发送”按钮后实时添加新行吗?以及在 iPhone 的“消息”中?
  • @RomanHouse 是的,您可以随时实时更新 tableview 行。诀窍是在调用insertRowsAtIndexPaths:withRowAnimation: 方法时更新您用来显示tableview 的任何数据模型。请注意,即使批量更新,您也可以一一插入它们。还记得在beginUpdatesendUpdates 之间调用。
  • @Sam Hmm.. 我不明白如何实时添加新行。使用编辑模式,这不是问题。但是如果不使用编辑模式并且我在文本字段中有一些值需要在 TableView 中添加,我应该怎么做?

标签: objective-c ios sqlite tableview


【解决方案1】:

要使用动画更新您的UITableView,您需要:

  1. 在您的UITableView 上调用beginUpdates
  2. 更新您的数据模型
  3. 插入/删除行和节
  4. 在您的UITableView 上调用endUpdates

要记住的几件事:

  • 如果您要删除一个部分,则不应同时从该部分中删除行(不必要,甚至可能导致错误)
  • 如果您要插入一个部分,则不应同时在该部分中插入行(如果单元格可见,UITableView 将调用numberOfRowsInSection:,后跟cellForRowAtIndexPath:)。

什么意思,更新我的数据模型?

如果您通过添加和删除行和部分来操作UITableView,那么您应该有一些方法可以在任何给定时刻跟踪UITableView 中当前的部分/行。

例如,您应该有一个类似于以下内容的numberOfRowsInSection: 方法:

- (NSInteger)numberOfRowsInSection:(NSInteger)section
{
    // You should have a way to get section data with an index (section)
    // The below example assumes an NSArray named self.mySectionCollection
    // exists for this purpose
    NSArray *sectionList = self.mySectionCollection;
    // You should have data associated with a section.  Below its assumed
    // this data is wrapped in an NSDictionary.  Data that might be in here
    // could include a height, a name, number of rows, etc...
    NSDictionary *sectionData = [sectionList objectAtIndex:section];

    NSInteger rowCount = 0;
    // SectionData should NEVER be nil at this point.  You could raise an
    // exception here, have a debug assert, or just return 0.
    if (sectionData)
    {
        rowCount = [[sectionData objectForKey:@"rowCount"] intValue];
    }
    return rowCount;
}

您可以通过多种不同方式存储有关部分/行的信息,包括使用 CoreData。关键是通过在beginUpdatesendUpdates 之间修改这个集合,你告诉UITableView 如何更新自己(它会根据需要查询numberOfRowsInSection:numberOfSectionscellForRowAtIndexPath:)。

编辑

我相信,如果您修改您的 insertRows: 方法以修改您的数据源 (messenges),同时您通知 UITableView 已发生更新,事情将开始为您正常工作。

尝试使用此代码:

-(IBAction)insertRows:(id)sender 
{
   MDAppDelegate *appDelegate = (MDAppDelegate *)[[UIApplication sharedApplication] delegate];
   UITableView *tV = (UITableView *)self.tableView;

   [tV beginUpdates];

   // UPDATE DATA MODEL IN BETWEEN beginUpdates and endUpdates
   int rowIndex = appDelegate.messenges.count + 1;
   [messenges insertObject:[[NSString alloc] initWithFormat:@"%@", _textField.text] 
                   atIndex:rowIndex];

   // Notify UITableView that updates have occurred
   NSArray *insertIndexPaths = [NSArray arrayWithObject: 
                                [NSIndexPath indexPathForRow:rowIndex inSection:1]];
   [tV insertRowsAtIndexPaths:insertIndexPaths 
             withRowAnimation:UITableViewRowAnimationRight];

   [tV endUpdates];
}

编辑#2

如果您仍然有问题,我会查看您在哪里设置 self.editing 标志。

- (NSInteger)tableView:(UITableView *)tableView 
 numberOfRowsInSection:(NSInteger)section 
{
    MDAppDelegate *appDelegate = (MDAppDelegate *)[[UIApplication sharedApplication] delegate];
    //add new variable to what rows will be +1
    NSUInteger numberOfRowsInSection = appDelegate.messenges.count; 
    if (self.editing) 
    {
        numberOfRowsInSection++;
    }
    return numberOfRowsInSection;
}

此标志控制表中是否存在附加行。为此,您必须将其设置在beginUpdatesendUpdates 之间,例如:

// assuming the editing flag is set from some IBAction
-addNewRow:(id)sender
{
   int row = ???;  // not sure where you want this new row

   [self.tableView beginUpdates]
   self.editing = YES;
   NSArray *insertIndexPaths = [NSArray arrayWithObject: 
                                [NSIndexPath indexPathForRow:row inSection:1]];
   [self.tableView insertRowsAtIndexPaths:insertIndexPaths
                         withRowAnimation:UITableViewRowAnimationRight];
   [self.tableView endUpdates];
}

如果您要删除添加的行,如果用户停止编辑,请记住同样调用deleteRowsAtIndexPaths:withRowAnimation:。我相信如果编辑变为永久性,则无需采取任何措施,但您需要设置self.editing = NO,同时在self.messenges 的适当位置添加新行。

另外,在您的 insertRows: 方法中,您告诉 UITableView 您在索引 1 处插入一行,而实际上您总是在 messenges 集合的末尾插入。我已经修改了 insertRows 方法的版本,使其具有 rowIndex 变量,以确保在更新数据模型时使用相同的索引并通知 UITableView 更改。

最后,当您遇到问题时,请提供尽可能多的调试信息。通常,当以您尝试的方式更新UITableView 出现问题时,它会告诉您存在不一致错误。自从我看到它已经有一段时间了,但大意是在更新表之前有 5 行,而在有 7 行之后,只添加了 1 行。如果它显示在您的控制台中,我希望看到此消息。

编辑#3

这是对您看到的错误的回应:

* 由于未捕获的异常“NSRangeException”而终止应用程序,原因:“* -[__NSArrayM objectAtIndex:]:索引 4 超出范围 [0 .. 3]'

您的错误与插入 UITableView 无关。这与您尝试插入超出数组边界的事实有关。我的猜测是违规行是:

[messenges insertObject:[[NSString alloc] initWithFormat:@"%@", 
                          _textField.text] 
                atIndex:appDelegate.messenges.count+1];

要在数组末尾插入,请使用索引appDelegate.messenges.count(删除了+1)。

另外...您是否绝对确定您的数据模型和更新 UITableView 的调用同意?尝试在调用beginUpdates 之后和调用endUpdates 之前调用NSLog(@"rowsBeforeUpdate: %i", [self numberOfRowsInSection:0]);。另外,在通知 UITableView 插入操作时调用NSLog(@"inserting index paths: %@", insertIndexPaths)。我的猜测是self.messenges 准确地反映了应该在表中的行,但是通过在self.tableView.editing 为真时添加+1,您将numberOfRowsInSection: 推到您在调用insertRowsAtIndexPaths:withRowAnimation: 时报告的内容之上。

试试这个:

-(IBAction)insertRows:(id)sender {
    MDAppDelegate *appDelegate = (MDAppDelegate *)[[UIApplication sharedApplication] delegate];
    [self.tableView beginUpdates];
    NSLog(@"rows before update: %i", [self numberOfRowsInSection:0]);

    self.tableView.editing = YES;
    NSLog(@"rows with editing flag set: %i", [self numberOfRowsInSection:0]);

    int rowIndex = appDelegate.messenges.count;  // don't need +1 at end
    int sectionIndex = 0;  // should it be 0 or 1?  I would guess 0
    [messenges insertObject:[[NSString alloc] initWithFormat:@"%@", _textField.text] 
                    atIndex:rowIndex];

    NSArray *insertIndexPaths = [NSArray arrayWithObject:
                                 [NSIndexPath indexPathForRow:rowIndex 
                                                    inSection:sectionIndex]];
    [self.tableView insertRowsAtIndexPaths:insertIndexPaths 
                          withRowAnimation:UITableViewRowAnimationRight];
    NSLog(@"inserting index paths: %@", insertIndexPaths);

    [self.tableView endUpdates];
}

我更改了上面的行索引以排除其中的+1。我将部分索引更改为 0,这应该是正确的,除非此 UITableView 实际上确实有多个未提及的部分。确保您的日志有意义。如果您在insertRows: 的过程中看到numberOfRowsInSection: 增加了2,那么您最好也看到insertRowsAtIndexPaths: 反映同样的事情。我很困惑为什么您需要编辑标志来在您的 numberOfRowsInSection: 方法中添加另一行。这部分(如果设置了self.editing,则添加一个额外的行)似乎无法正常工作。也许只是尝试省略这部分以使其某些工作正常,然后在某些事情正常工作后将其重新添加。也许将 numberOfRowsInSection: 更改为如下所示,直到某些事情开始起作用:

- (NSInteger)tableView:(UITableView *)tableView 
 numberOfRowsInSection:(NSInteger)section 
{
    MDAppDelegate *appDelegate = (MDAppDelegate *)[[UIApplication sharedApplication] delegate];
    NSUInteger numberOfRowsInSection = appDelegate.messenges.count;
    NSLog(@"numberOfRowsInSection %i: %u", section, numberOfRowsInSection);
    return numberOfRowsInSection;
}

【讨论】:

  • 使用了您的代码。但我仍然有同样的错误。也许我们忘记了什么?
  • 我会看两件事,1.) 在您的 insertRows: 方法中,您需要更新 self.messenges 中的相同索引以及您对 insertRowsAtIndexPaths:withRowAnimation: 的调用。目前,您添加到self.messenges 的末尾,但是当您调用insertRowsAtIndexPaths:withRowAnimation: 时,您传递了1 的行索引。 2.) 确保在更改 self.editing 变量时正确添加/删除一行,因为这会影响 numberOfRowsInSection: 中返回的内容。我已经更详细地更新了我的答案。
  • 您看到的错误是 b/c 您尝试将其插入 self.messenges 的末尾。例如,如果数组self.messenges 中的计数为 2,则可以使用 0 到 2 之间的索引插入。0 将在任何其他项目之前,1 在第一项之后,2(计数)将在第二项之后(即它将插入到结束)。我用更多细节修改了我的答案。希望事情开始对你有用。
  • 我们可以聊天吗?我对您的代码有一些疑问。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-15
  • 2019-09-09
  • 2012-11-14
  • 2018-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多