我正在进行聊天应用程序并从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.'
我该如何解决?
EDIT2
确定。我只有一节。 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;}
但我仍然有同样的错误。
我们来看看。我将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'的错误。
答案 0 :(得分:7)
UITableView
,您需要:beginUpdates
UITableView
endUpdates
UITableView
醇>
UITableView
会调用numberOfRowsInSection:
,然后调用cellForRowAtIndexPath:
。如果您通过添加和删除行和部分来操作UITableView
,那么您应该有一些方法可以在任何给定时刻跟踪UITableView
中当前哪些部分/行。< / p>
例如,您应该使用类似于此的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。关键是,通过在beginUpdates
和endUpdates
之间修改此集合,您告诉UITableView
如何更新自身(它将查询numberOfRowsInSection:
,numberOfSections
,和cellForRowAtIndexPath:
根据需要)。
我相信,如果您修改了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];
}
如果您仍有问题,我会查看您设置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;
}
此标志控制表中是否存在其他行。因此,您必须在beginUpdates
和endUpdates
之间进行设置,如:
// 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
的末尾插入{1}}集合。我修改了insertRows
方法的版本,使其具有rowIndex
变量,以确保在更新数据模型时使用相同的索引并通知UITableView
更改
最后,请在遇到问题时尽可能多地包含调试信息。通常,当您以尝试的方式更新UITableView
时出现问题时,它会告诉您存在不一致错误。我已经看过它已经有一段时间了,但是在更新表之前有5行数,之后有7行时只添加了1行。如果它出现在您的控制台中,我希望看到此消息。
这是对您所看到的错误的回应:
*由于未捕获的异常'NSRangeException'终止应用程序,原因:'* - [__ NSArrayM objectAtIndex:]:索引4超出边界[0 .. 3]“
您的错误与插入UITableView无关。它与您尝试插入超出数组边界的事实有关。我的猜测是违规行:
[messenges insertObject:[[NSString alloc] initWithFormat:@"%@",
_textField.text]
atIndex:appDelegate.messenges.count+1];
要在数组末尾插入,请使用appDelegate.messenges.count
索引(删除+1
)。
另外......您是否完全确定您的数据模型和更新UITableView的调用是否一致?在致电NSLog(@"rowsBeforeUpdate: %i", [self numberOfRowsInSection:0]);
之前和呼叫beginUpdates
之前,请尝试调用endUpdates
。另外,在通知UITableView插入操作时调用NSLog(@"inserting index paths: %@", insertIndexPaths)
。我的猜测是self.messenges
准确地反映了表格中应该包含的行,但是当+1
为真时添加self.tableView.editing
,您可以将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
。我将section index更改为0,这应该是正确的,除非这个UITableView确实有多个未提及的部分。确保您的日志有意义。如果您在numberOfRowsInSection:
期间看到insertRows:
增加了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;
}