Чтобы обновить UITableView
с анимацией, вам необходимо:
- Вызвать
beginUpdates
на вашем UITableView
- Обновление модели данных
- Вставка / удаление строк и разделов
- Вызов
endUpdates
на вашем UITableView
Несколько вещей, о которых следует помнить:
- Если вы удаляете раздел, вы не должны также удалять строки из этого раздела (ненужные и даже могут вызвать ошибки)
- Если вы вставляете раздел, вы не должны также вставлять строки в этот раздел (
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.Дело в том, что, изменяя эту коллекцию в промежутке между 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];
}
Edit # 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;
}
Этот флагопределяет, существует ли в таблице дополнительная строка или нет.По этой причине вы должны установить его между 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
.Я изменил свою версию метода 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 согласны? Попробуйте вызвать NSLog(@"rowsBeforeUpdate: %i", [self numberOfRowsInSection:0]);
сразу после вызова beginUpdates
и непосредственно перед вызовом endUpdates
. Кроме того, вызовите NSLog(@"inserting index paths: %@", insertIndexPaths)
при информировании UITableView об операции вставки. Я предполагаю, что self.messenges
точно отражает строки, которые должны быть в таблице, но добавляя +1
, когда self.tableView.editing
имеет значение true, вы нажимаете 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 не имеет несколько разделов, которые не были упомянуты. Убедитесь, что ваши логи имеют смысл. Если вы увидите, что numberOfRowsInSection:
увеличится на два в течение insertRows:
, тогда вам также лучше увидеть, как 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;
}