Dưới đây là một giải pháp đầy đủ như thế nào để quản lý một bảng chỉ mục với dữ liệu cốt lõi . Thuộc tính của bạn được gọi là displayOrder
, tôi gọi nó là index
. Trước hết, bạn nên xem bộ điều khiển và mô hình riêng biệt tốt hơn. Đối với điều này tôi sử dụng một bộ điều khiển mô hình, đó là giao diện giữa khung nhìn và mô hình.
Có 3 trường hợp bạn cần quản lý để người dùng có thể ảnh hưởng thông qua bộ điều khiển chế độ xem.
- Thêm một đối tượng mới
- Xóa một đối tượng hiện
- đối tượng Sắp xếp lại.
Hai trường hợp đầu tiên Thêm và xóa khá đơn giản. Xóa các cuộc gọi một thói quen gọi là renewObjectIndicesUpwardsFromIndex
để cập nhật các chỉ số sau khi đối tượng đã xóa.
- (void)createObjectWithTitle:(NSString*)title {
FFObject* object = [FFObject insertIntoContext:self.managedObjectContext];
object.title = title;
object.index = [NSNumber numberWithInteger:[self numberTotalObjects]];
[self saveContext];
}
- (void)deleteObject:(FFObject*)anObject {
NSInteger objectIndex = [anObject.index integerValue];
[anObject deleteObject];
[self renewObjectIndicesUpwardsFromIndex:objectIndex];
[self saveContext];
}
- (void)renewObjectIndicesUpwardsFromIndex:(NSInteger)fromIndex {
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:@"Object" inManagedObjectContext:self.managedObjectContext]];
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"(index > %d)", fromIndex];
[fetchRequest setPredicate:predicate];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"index" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSError* fetchError = nil;
NSArray* objects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&fetchError];
NSInteger index = fromIndex;
for (FFObject* object in objects) {
object.index = [NSNumber numberWithInteger:index];
index += 1;
}
[self saveContext];
}
Trước khi đến phần điều khiển để sắp xếp lại, ở đây trong bộ điều khiển chế độ xem. Tôi sử dụng bool isModifyingOrder
tương tự như this answer. Lưu ý rằng bộ điều khiển xem gọi hai chức năng trong bộ điều khiển moveObjectOrderUp
và moveObjectOrderDown
. Tùy thuộc vào cách bạn hiển thị các đối tượng trong chế độ xem bảng - mới nhất trước tiên hoặc mới nhất - bạn có thể chuyển đổi chúng.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
isModifyingOrder = YES;
NSUInteger fromIndex = sourceIndexPath.row;
NSUInteger toIndex = destinationIndexPath.row;
if (fromIndex == toIndex) {
return;
}
FFObject *affectedObject = [self.fetchedResultsController.fetchedObjects objectAtIndex:fromIndex];
NSInteger delta;
if (fromIndex < toIndex) {
delta = toIndex - fromIndex;
NSLog(@"Moved down by %lu cells", delta);
[self.objectController moveObjectOrderUp:affectedObject by:delta];
} else {
delta = fromIndex - toIndex;
NSLog(@"Moved up by %lu cells", delta);
[self.objectController moveObjectOrderDown:affectedObject by:delta];
}
isModifyingOrder = NO;
}
Và đây là bộ phận của bộ điều khiển. Điều này có thể được viết đẹp hơn, nhưng đối với sự hiểu biết này có lẽ là tốt nhất.
- (void)moveObjectOrderUp:(FFObject*)affectedObject by:(NSInteger)delta {
NSInteger fromIndex = [affectedObject.index integerValue] - delta;
NSInteger toIndex = [affectedObject.index integerValue];
if (fromIndex < 1) {
return;
}
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:@"Object" inManagedObjectContext:self.managedObjectContext]];
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"(index >= %d) AND (index < %d)", fromIndex, toIndex];
[fetchRequest setPredicate:predicate];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"index" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSError* fetchError = nil;
NSArray* objects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&fetchError];
for (FFObject* object in objects) {
NSInteger newIndex = [object.index integerValue] + 1;
object.index = [NSNumber numberWithInteger:newIndex];
}
affectedObject.index = [NSNumber numberWithInteger:fromIndex];
[self saveContext];
}
- (void)moveObjectOrderDown:(FFObject*)affectedObject by:(NSInteger)delta {
NSInteger fromIndex = [affectedObject.index integerValue];
NSInteger toIndex = [affectedObject.index integerValue] + delta;
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:@"Object" inManagedObjectContext:self.managedObjectContext]];
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"(index > %d) AND (index <= %d)", fromIndex, toIndex];
[fetchRequest setPredicate:predicate];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"index" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSError* fetchError = nil;
NSArray* objects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&fetchError];
for (FFObject* object in objects)
{
NSInteger newIndex = [object.index integerValue] - 1;
object.index = [NSNumber numberWithInteger:newIndex];
}
affectedObject.index = [NSNumber numberWithInteger:toIndex];
[self saveContext];
}
Đừng quên sử dụng giây thứ hai BOOL
trong trình điều khiển chế độ xem để xóa hành động để ngăn thông báo di chuyển làm bất cứ điều gì. Tôi gọi nó là isDeleting
và đặt nó ở đây.
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
if (isModifyingOrder) return;
...
switch(type) {
...
case NSFetchedResultsChangeMove:
if (isDeleting == false) {
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:localIndexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:localNewIndexPath]withRowAnimation:UITableViewRowAnimationFade];
}
break;
...
}
}
Tuyệt vời! Điều này làm việc hoàn hảo. Tôi rất muốn nhìn chằm chằm vào mã gốc quá lâu - cảm ơn vì sự giúp đỡ của bạn. –
Điều này cần được triển khai song song với http://stackoverflow.com/questions/1077568/how-to-implement-re-ordering-of-coredata-records/2013070#2013070 –
Nếu các mục có thể bị xóa, điều này không công việc. Bạn phải đảm bảo cập nhật trường đơn đặt hàng cũng khi xóa một hàng. – Kamchatka