Tearing my hair out trying to get this to work. I want to perform [self.tableView deleteRowsAtIndexPaths:indexes withRowAnimation:UITableViewRowAnimationLeft];
,
More detailed code of how I delete:
int index = (int)[self.messages indexOfObject:self.messageToDelete];
[self.messages removeObject:self.messageToDelete];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
NSArray *indexes = [[NSArray alloc] initWithObjects:indexPath, nil];
[self.tableView deleteRowsAtIndexPaths:indexes withRowAnimation:UITableViewRowAnimationLeft];
This works fine however if I get a push notification (i.e a new message received) whilst deleting the app will crash and display an error like:
Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit/UIKit-3347.44/UITableView.m:1327 2015-07-04 19:12:48.623 myapp[319:24083] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to delete row 1 from section 0 which only contains 1 rows before the update'
I suspect this is because my data source is changing, the size of the array that
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
references while deleting won't be consistent because it was incremented by one when the push notification triggered a refresh. Is there any way I can work around this? Am I correct that deleteRowsAtIndexPaths
uses the numberOfRowsInSection
method?
Parameterize your connection string with query parameter then you can achieve dynamic change the data source on power bi service side. But this seems not suitable for your scenario, it look more complex than change on single data source.
Unfortunately, it isn't really possible to carry out what you want to achieve. I think if PowerApps provided the ability for users to dynamically change a data source at runtime, it would be a great addition to the product.
I think if PowerApps provided the ability for users to dynamically change a data source at runtime, it would be a great addition to the product. The workarounds that people use generally use involve adding all possible data sources to an app and providing some dropdown to load the data source into a collection.
But as you know, Power BI will complain that the file paths of the data sources do not exist. Is there a way to decouple the data paths in the report, so it points to the just the subfolder and won't require a full path including the C:\User portion of it? Solved! Go to Solution. 12-27-2018 12:36 AM Yes, your requirement can be achieved.
So, in order to solve your problem you need to ensure that your data source will not change while some table view animations are in place. I would propose to do the following.
First, create two arrays: messagesToDelete
and messagesToInsert
. These will hold information about which messages you want to delete/insert.
Second, add a Boolean property updatingTable
to your table view data source.
Third, add the following functions:
-(void)updateTableIfPossible {
if (!updatingTable) {
updatingTable = [self updateTableViewWithNewUpdates];
}
}
-(BOOL)updateTableViewWithNewUpdates {
if ((messagesToDelete.count == 0)&&(messagesToInsert.count==0)) {
return false;
}
NSMutableArray *indexPathsForMessagesThatNeedDelete = [[NSMutableArray alloc] init];
NSMutableArray *indexPathsForMessagesThatNeedInsert = [[NSMutableArray alloc] init];
// for deletion you need to use original messages to ensure
// that you get correct index paths if there are multiple rows to delete
NSMutableArray *oldMessages = [self.messages copy];
for (id message in messagesToDelete) {
int index = (int)[self.oldMessages indexOfObject:message];
[self.messages removeObject:message];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
[indexPathsForMessagesThatNeedDelete addObject:indexPath];
}
for (id message in messagesToInsert) {
[self.messages insertObject:message atIndex:0];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[indexPathsForMessagesThatNeedInsert addObject:indexPath];
}
[messagesToDelete removeAllObjects];
[messagesToInsert removeAllObjects];
// at this point your messages array contains
// all messages which should be displayed at CURRENT time
// now do the following
[CATransaction begin];
[CATransaction setCompletionBlock:^{
updatingTable = NO;
[self updateTableIfPossible];
}];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:indexPathsForMessagesThatNeedDelete withRowAnimation:UITableViewRowAnimationLeft];
[tableView insertRowsAtIndexPaths:indexPathsForMessagesThatNeedInsert withRowAnimation:UITableViewRowAnimationLeft];
[tableView endUpdates];
[CATransaction commit];
return true;
}
Lastly, you need to have the following code in all functions which want to add/delete rows.
To add message
[self.messagesToInsert addObject:message];
[self updateTableIfPossible];
To delete message
[self.messagesToDelete addObject:message];
[self updateTableIfPossible];
What this code does is ensures stability of your data source. Whenever there is a change you add the messages that need to be inserted/deleted into arrays (messagesToDelete
and messagesToDelete
). You then call a function updateTableIfPossible
which will update the table view's data source (and will animate the change) provided that there is no current animation in progress. If there is an animation in progress it will do nothing at this stage.
However, because we have added a completion
[CATransaction setCompletionBlock:^{
updatingTable = NO;
[self updateTableIfPossible];
}];
at the end of the animations our data source will check if there are any new changes that need to be applied to the table view and, if so, it will update the animation.
This is a much safer way of updating your data source. Please let me know if it works for you.
Delete a Row
int index = (int)[self.messages indexOfObject:self.messageToDelete];
[self.messages removeObject:self.messageToDelete];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
[tableView endUpdates];
Delete a Section
Note : if your TableView have multiple section than you have to delete whole section when section contain only one row instead of deleting row
int index = (int)[self.messages indexOfObject:self.messageToDelete];
[self.messages removeObject:self.messageToDelete];
NSIndexPath *indexPath = [NSIndexSet indexSetWithIndex:0];
[tableView beginUpdates];
[tableView deleteSections:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
[tableView endUpdates];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With