I’m making chat application and read messages data from SQLite database. I want to reload my TableView data with new messages after clicking on my “send” button.
Event for my button:
[_sendButton addTarget:self action:@selector(saveMessage:) forControlEvents:UIControlEventTouchUpInside];
I think I need to use -(void)viewDidAppear:(BOOL)animated but it didn’t work (or I’m doing something wrong).
[_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);}
Editing
This is my method to add a new row to TableView. New row must be added at once after clicking “send” button.
-(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];}
But this code give me error: '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.'
How can I fix it?
Edit2
Ok. I have only 1 section. numberOfSectionsInTableView: does not require correction.
- (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;}
But I still have the same error.
Edit #3
Let’s look. I changed my insertRows to :
-(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];
}
And 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;
}
But I got an error *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 4 beyond bounds [0 .. 3]' . Then I corrected if (self.tableView.editing) to:
if (self.tableView.editing) {
MDAppDelegate *someNewDelegate = (MDAppDelegate *)[[UIApplication sharedApplication] delegate];
numberOfRowsInSection = someNewDelegate.messenges.count+1; //or .count
}
But got same error about ‘NSRangeException’.
To update your
UITableViewwith animation you need to:beginUpdateson yourUITableViewendUpdateson yourUITableViewCouple of Things to Keep in Mind:
UITableViewwill callnumberOfRowsInSection:followed bycellForRowAtIndexPath:if the cell is visible).What Do You Mean, Update My Data Model?
If you are manipulating a
UITableViewby adding and removing rows and sections, then you should have some way of keeping track of what sections / rows are currently in theUITableViewat any given moment.For example, you should have a
numberOfRowsInSection:method that resembles this:You can store information about sections / rows in several different ways including using CoreData. The point is that by modifying this collection in between
beginUpdatesandendUpdatesyou are telling theUITableViewhow to update itself (it will querynumberOfRowsInSection:,numberOfSections, andcellForRowAtIndexPath:as needed).Edit
I believe if you modify your
insertRows:method to modify your data source (messenges) at the same time you notifyUITableViewthat updates have occurred that things will begin working for you properly.Try using this code:
Edit #2
If you are still having issues, I would look at where you are setting the
self.editingflag.This flag controls whether an additional row exists in the table or not. For this reason, you must set it between
beginUpdatesandendUpdateslike:Remember to similarly call
deleteRowsAtIndexPaths:withRowAnimation:if the user stops editing if you are removing the row you add. I believe no action is necessary if the edit becomes permanent, but you’d need to setself.editing = NOwhile also adding a new row to it’s proper place inself.messenges.Also, in your
insertRows:method, you telling theUITableViewthat you are inserting a row at index 1 when in fact you always insert at the end of themessengescollection. I’ve modified my version of theinsertRowsmethod so that it has arowIndexvariable for the purpose of ensuring the same index is used when updating the data model and informingUITableViewof the change.Lastly, please include as much debugging information as possible when you run into problems. Usually when a problem arises from updating the
UITableViewin the manner you are trying, it will tell you there is an inconsistency error. It’s been awhile since I’ve seen it, but something to the effect that before updating the table there were 5 number of rows and after there were 7 when only 1 was added. I’d like to see this message if it is showing up in your console.Edit #3
This is in response to the error you are seeing:
Your error has nothing to do with inserting into the UITableView. It has to do with the fact that you are trying to insert beyond the bounds of an array. My guess is the offending line is:
To insert at the end of the array, use an index of
appDelegate.messenges.count(removed the+1).Also… Are you absolutely certain your data model and calls to update the UITableView agree? Try invoking
NSLog(@"rowsBeforeUpdate: %i", [self numberOfRowsInSection:0]);just after you callbeginUpdatesand just before callingendUpdates. Also, callNSLog(@"inserting index paths: %@", insertIndexPaths)when informing the UITableView of an insert operation. My guess is thatself.messengesaccurately reflects the rows that should be in the table, but by adding+1whenself.tableView.editingis true, you push thenumberOfRowsInSection:above what you report in your calls toinsertRowsAtIndexPaths:withRowAnimation:.Try this:
I changed the row index above to exclude the
+1in it. I changed the section index to be 0, which should be correct unless this UITableView does in fact have multiple sections that haven’t been mentioned. Make sure that your logs make sense. If you seenumberOfRowsInSection:increase by two during the course ofinsertRows:then you had also better seeinsertRowsAtIndexPaths:reflect the same thing. I’m confused why you need the editing flag to add another row in yournumberOfRowsInSection:method. This part (where you add an additional row ifself.editingis set) doesn’t seem to be working right. Perhaps just try leaving out this part to have some of it working, then add it back in once you have some things working properly. Perhaps changenumberOfRowsInSection:to be like the following until some things begin working: