Refresh TableView data after button click

I am making a chat app and reading messages from a SQLite database. I want to reload the TableView data with new messages after clicking on the submit 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);}

      

edit This is my method of adding a new row to the TableView. The new line should be added immediately after clicking the "Submit" 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 is giving me an 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 this?

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

We'll see. I changed mine 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 adjusted if (self.tableView.editing)

to:

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

      

But the same error appeared regarding "NSRangeException".

+3


source to share


1 answer


To update UITableView

with animation you need:

A couple of things to remember:

What do you mean update my data model?

If you are in control of UITableView

adding and removing rows and sections, you should have some way of keeping track of which sections / rows are UITableView

at any given moment.

For example, you should have a method numberOfRowsInSection:

that resembles this:

- (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;
}

      

You can store section / line information in several ways, including using CoreData. The fact is that by changing this collection between beginUpdates

and endUpdates

you are telling UITableView

how to update itself (it will ask numberOfRowsInSection:

, numberOfSections

and cellForRowAtIndexPath:

as needed).

Edit

I believe that if you change your method insertRows:

to change the datasource ( messenges

), in the meantime, you communicate UITableView

that updates have occurred, that everything will start working for you as expected.

Try using this code:

-(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];
}

      

Edit # 2

If you still have problems I would take a look where you set the flag 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;
}

      



This flag determines whether an additional table exists in the table or not. For this reason, you must set it between beginUpdates

and endUpdates

like this:

// 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];
}

      

Remember to also call deleteRowsAtIndexPaths:withRowAnimation:

if the user stops editing if you remove the added row. I believe no action is required if the edit becomes permanent, but you need to install self.editing = NO

as well as add a new line at the correct location in self.messenges

.

Also , in your method, insertRows:

you say UITableView

that you are inserting a row at index 1, when in fact you are always inserting at the end of the collection messenges

. I changed my version of the method insertRows

to have a variable rowIndex

in order to ensure that the same index is used when updating the data model and informing about the change UITableView

.

Finally, please include as much debugging information as possible when you run into problems. Usually when there is a problem with an update UITableView

in the way you are trying it will tell you that there is an inconsistency error. It has been a while since I saw it, but something that looks like there were 5 rows before the table was updated and only 1 was added after 7. I'd like to see this message if it popped up in your console.

Edit # 3

This is the answer to the error you are seeing:

* Application terminated due to uncaught "NSRangeException", reason: "* - [__ NSArrayM objectAtIndex:]: index 4 out of bounds [0 .. 3] '

Your error has nothing to do with nesting in a UITableView. This is because you are trying to insert outside of the array. I guess this is a violation:

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

      

To insert at the end of an array, use index appDelegate.messenges.count

(deleted +1

).

Also ... are you absolutely sure your data model and calls to update the UITableView agree? Try calling NSLog(@"rowsBeforeUpdate: %i", [self numberOfRowsInSection:0]);

immediately after the call beginUpdates

and just before the call endUpdates

. Also, call NSLog(@"inserting index paths: %@", insertIndexPaths)

when informing the UITableView of the insert operation. I am assuming that it self.messenges

accurately reflects the rows that should be in the table, but adding +1

when self.tableView.editing

is true, you push numberOfRowsInSection:

above what you report in your calls to insertRowsAtIndexPaths:withRowAnimation:

.

Try the following:

-(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];
}

      

I changed the line index above to exclude +1

in it. I changed the section index to 0, which should be correct, unless this UITableView actually has multiple sections that were not mentioned. Make sure your magazines make sense. If you see what numberOfRowsInSection:

has increased by two over the course insertRows:

, you would also be better off seeing what insertRowsAtIndexPaths:

reflects the same . I am confused why you need an edit flag to add another line to your method numberOfRowsInSection:

. This part (where you add an extra line if installed self.editing

) doesn't seem to work correctly. Maybe just try to keep that part so some of it works, then add it back in once you have something that works fine. Perhaps changenumberOfRowsInSection:

as follows, until some things start working:

- (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;
}

      

+7


source







All Articles