How should I handle the NSIndexSet from kvo to upd

2019-03-21 18:53发布

问题:

I am starting out using key value observing, and the mutable array I'm observing gives me NSIndexSets (Ordered mutable to-many) in the change dictionary. The problem is the table view as far as I know wants me to give it NSArrays full of indexes.

I thought about implementing a custom method to translate one to the other, but this seems slow and I get the impression there must be a better way to make this table view update when the array changes.

This is the method from my UITableViewDataSource.

 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
     switch ([[change valueForKey:NSKeyValueChangeKindKey] unsignedIntValue]) {
         case NSKeyValueChangeSetting:
             NSLog(@"Setting Change");
             break;
         case NSKeyValueChangeInsertion:
             NSLog(@"Insertion Change");

             // How do I fit this:
             NSIndexSet * indexes = [change objectForKey:NSKeyValueChangeIndexesKey];

             // into this:
             [self.tableView insertRowsAtIndexPaths:<#(NSArray *)#> withRowAnimation:<#(UITableViewRowAnimation)#>

             // Or am I just doing it wrong?

             break;
         case NSKeyValueChangeRemoval:
             NSLog(@"Removal Change");
             break;
         case NSKeyValueChangeReplacement:
             NSLog(@"Replacement Change");
             break;
         default:
             break;
     }
 }

回答1:

This seems easy enough. Enumerate the index set using enumerateIndexesUsingBlock: and stick each index into an NSIndexPath object:

NSMutableArray * paths = [NSMutableArray array];
[indexes enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) {
        [paths addObject:[NSIndexPath indexPathWithIndex:index]];
    }];
[self.tableView insertRowsAtIndexPaths:paths
                      withRowAnimation:<#(UITableViewRowAnimation)#>];

If your table view has sections, it's only a bit more complicated, because you'll need to get the correct section number, and specify it in the index path:

NSUInteger sectionAndRow[2] = {sectionNumber, index};
[NSIndexPath indexPathWithIndexes:sectionAndRow
                           length:2];


回答2:

Here's a category for NSIndexSet:

@interface NSIndexSet (mxcl)
- (NSArray *)indexPaths;
@end

@implementation NSIndexSet (mxcl)

- (NSArray *)indexPaths {
    NSUInteger rows[self.count];
    [self getIndexes:rows maxCount:self.count inIndexRange:NULL];
    NSIndexPath *paths[self.count];
    for (int x = 0; x < self.count; ++x)
        paths[x] = [NSIndexPath indexPathForRow:rows[x] inSection:0];
    return [NSArray arrayWithObjects:paths count:self.count];
}

@end

Code would be shorter with an NSMutableArray, but something in me tries to resist making mutable objects when the result is intended to be constant.