重新排列单元格后如何更改fetchresultcontroller数组中对象的顺序

尼克·希米克

我有一个表格视图,我刚刚实现了一个类,该类可以帮助我重新排列单元格,例如表格视图委托附带的常规移动单元格方法。

现在,在对单元格重新排序之后,我需要将保存单元格对象的数组更改为新的顺序...我该怎么做?

这是我重新排序单元格的方法:

- (void)moveTableView:(FMMoveTableView *)tableView moveRowFromIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { NSArray 

}

我有一个coreDataStack类,该类负责处理所有核心数据(创建singelton),它看起来像这样:

#import "CoreDataStack.h"

@implementation CoreDataStack

#pragma mark - Core Data stack

@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;

+ (instancetype)defaultStack {

    static CoreDataStack *defaultStack;
    static dispatch_once_t onceTocken;
    dispatch_once (&onceTocken, ^{
        defaultStack = [[self alloc] init];
    });

    return defaultStack;
}


- (NSURL *)applicationDocumentsDirectory {
    // The directory the application uses to store the Core Data store file. This code uses a directory named "digitalCrown.Lister" in the application's documents directory.
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

- (NSManagedObjectModel *)managedObjectModel {
    // The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
    if (_managedObjectModel != nil) {
        return _managedObjectModel;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Lister" withExtension:@"momd"];
    _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    return _managedObjectModel;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    // The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it.
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

    // Create the coordinator and store

    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Lister.sqlite"];
    NSError *error = nil;
    NSString *failureReason = @"There was an error creating or loading the application's saved data.";
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        // Report any error we got.
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
        dict[NSLocalizedFailureReasonErrorKey] = failureReason;
        dict[NSUnderlyingErrorKey] = error;
        error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
        // Replace this with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    return _persistentStoreCoordinator;
}


- (NSManagedObjectContext *)managedObjectContext {
    // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
    if (_managedObjectContext != nil) {
        return _managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (!coordinator) {
        return nil;
    }
    _managedObjectContext = [[NSManagedObjectContext alloc] init];
    [_managedObjectContext setPersistentStoreCoordinator:coordinator];
    return _managedObjectContext;
}

#pragma mark - Core Data Saving support

- (void)saveContext {
    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil) {
        NSError *error = nil;
        if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
            // Replace this implementation with code to handle the error appropriately.
            // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
    }
}


@end

每当我将新对象添加到核心数据时,我都会这样做:

- (void)insertTeget {

    CoreDataStack *stack = [CoreDataStack defaultStack];
    Target *target = [NSEntityDescription insertNewObjectForEntityForName:@"Target" inManagedObjectContext:stack.managedObjectContext];
    if (self.myTextView.text != nil) {
        target.body = self.myTextView.text;
        target.time = [NSDate date];
    }

    [stack saveContext];

}

在表视图中,当我获取数据时,我这样做:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {


    static NSString *cellIdentifier = @"StackTableViewCell";

    Target *target = [self.fetchedResultController objectAtIndexPath:indexPath];

    StackTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

    if (!cell)
    {
        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"StackTableViewCell" owner:self options:nil];
        cell = [topLevelObjects objectAtIndex:0];
    }

    cell.cellLabel.text = target.body;

    cell.cellLabel.font = [UIFont fontWithName:@"Candara-Bold" size:20];

    cell.showsReorderControl = YES;



    // Configure the cell...

    return cell;
}

这是我在表视图控制器类中的fetchresultconroller / fetch请求配置:

- (NSFetchRequest *)targetsFetchRequest {

    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Target"];
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"time" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
    [fetchRequest setSortDescriptors:sortDescriptors];
    return fetchRequest;
}


- (NSFetchedResultsController *)fetchedResultController {

    if (_fetchedResultController != nil) {
        return _fetchedResultController;
    }

    CoreDataStack *stack = [CoreDataStack defaultStack];

    NSFetchRequest *fetchRequest = [self targetsFetchRequest];

    _fetchedResultController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:stack.managedObjectContext sectionNameKeyPath:nil cacheName:nil];

    _fetchedResultController.delegate = self;

    return _fetchedResultController;

}

我要完成的工作是,每当用户创建目标对象时,它将到达数组的末尾(因此它将像一个队列),并且如果用户移动了单元格,那么我需要更改数组的顺序。数据库...

移动细胞方法:

- (void)moveTableView:(FMMoveTableView *)tableView moveRowFromIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {

    int start = 0;
    int end = 0;
    if (fromIndexPath.row > toIndexPath.row) {
        start = (int)fromIndexPath.row;
        end = (int)toIndexPath.row;
    } else {
        start = (int)toIndexPath.row;
        end = (int)fromIndexPath.row;
    }

    for (int i = start; i <= end; ++i) {
        Target *target = [self.fetchedResultController objectAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
        [target setOrder:@(i)];
    }

    [[CoreDataStack defaultStack] saveContext];


    // a test to see if the order is changed
    [self.fetchedResultController performFetch:nil];

    NSArray *arr = [self.fetchedResultController fetchedObjects];
    for (int i=0; i<arr.count; i++)  {
        Target *ta = [arr objectAtIndex:i];
        NSLog(@"%@",ta.body);
    }
}

日志:

2015-04-14 10:29:13.405 Lister[3163:477453] One
2015-04-14 10:29:13.406 Lister[3163:477453] Two
2015-04-14 10:29:13.406 Lister[3163:477453] Three
2015-04-14 10:29:13.407 Lister[3163:477453] Four
2015-04-14 10:29:13.407 Lister[3163:477453] Five
2015-04-14 10:29:21.070 Lister[3163:477453] 

2015-04-14 10:29:21.071 Lister[3163:477453] One
2015-04-14 10:29:21.071 Lister[3163:477453] Two
2015-04-14 10:29:21.071 Lister[3163:477453] Three
2015-04-14 10:29:21.072 Lister[3163:477453] Four
2015-04-14 10:29:21.072 Lister[3163:477453] Five
2015-04-14 10:29:25.037 Lister[3163:477453] 

2015-04-14 10:29:25.039 Lister[3163:477453] One
2015-04-14 10:29:25.039 Lister[3163:477453] Two
2015-04-14 10:29:25.040 Lister[3163:477453] Three
2015-04-14 10:29:25.040 Lister[3163:477453] Four
2015-04-14 10:29:25.041 Lister[3163:477453] Five

另外,如果将带有标签“一”的单元格移动到带有标签“二”的单元格的索引,则单元格的标签现在变得很奇怪,因此“一”的标签将变为“二”。因此,我想到了2个单元格具有相同标签的情况。

布尔汉丁·苏尼尔瓦拉

那么最简单的解决方案是

  1. 向您的Target实体添加一个属性,说出其order类型Integer32

创建和插入新对象

  1. 每当创建新Target对象时,都首先使用sortDescriptor具有key@"order"和的从数据库中获取现有对象ascending=YES取得此提取数组的最后一个对象并检查其顺序。现在,在您的新Target对象中,递增顺序并将其插入数据库。如果获取的数组返回0个对象,则设置order=@(0)

    - (void)insertTeget {
    
        CoreDataStack *stack = [CoreDataStack defaultStack];
    
        //Fetching objects from database
        NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Target"];
        NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"order" ascending:YES];
        [fetchRequest setSortDescriptors:@[sortDescriptor]];
        NSArray *existingObjects = [stack.managedObjectContext executeFetchRequest:fetchRequest error:nil];
    
        //Creating new object
        Target *target = [NSEntityDescription insertNewObjectForEntityForName:@"Target" inManagedObjectContext:stack.managedObjectContext];
        if (self.myTextView.text != nil) {
            target.body = self.myTextView.text;
            target.order = @([(Target *)existingObjects.lastObject order].integerValue + 1);
        }
    
        [stack saveContext];
    }
    

NSFetchedResultsController

  1. 使用上面定义的获取对象sortDescriptor

取自您的代码

    - (NSFetchRequest *)targetsFetchRequest {

        NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Target"];
        NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"order" ascending:YES];
        NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
        [fetchRequest setSortDescriptors:sortDescriptors];
        return fetchRequest;
    }


    - (NSFetchedResultsController *)fetchedResultController {

        if (_fetchedResultController != nil) {
            return _fetchedResultController;
        }

        CoreDataStack *stack = [CoreDataStack defaultStack];
        NSFetchRequest *fetchRequest = [self targetsFetchRequest];
        _fetchedResultController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:stack.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
        _fetchedResultController.delegate = self;
        return _fetchedResultController;
    }

重新排列单元

  1. 现在,当您在表格视图中重新排列单元格时,只需要运行一个for循环并更新其顺序即可。您只需要更新order两个indexPath之间的对象。

    - (void)moveTableView:(FMMoveTableView *)tableView moveRowFromIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {  
    
        int start = 0;
        int end = 0;
        if (fromIndexPath.row > toIndexPath.row) {
            start = fromIndexPath.row;
            end = toIndexPath.row;
        } else {
            start = toIndexPath.row;
            end = fromIndexPath.row;
        }
    
        for (int i = start; i <= end; ++i) {
            Target *target = [self.fetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
            [target setOrder:@(i)];
        }
    
        [[CoreDataStack defaultStack] saveContext];
    }
    

注意:以上解决方案假定您order从0开始。


在创建和插入新Target对象时,需要实现NSFetchedResultsController委托方法以为这些对象添加相应的行。由于我们已经定义了sortDescriptor,因此将在的末尾添加新行tableView

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView beginUpdates];
}


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
    atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {

    switch(type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
                            withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
    atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
    newIndexPath:(NSIndexPath *)newIndexPath {

    UITableView *tableView = self.tableView;

    switch(type) {

        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                       withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate:
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                       withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                       withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView endUpdates];
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

重新排列Cognos 10中单元格的内容

如何在Excel中的不同列中的多个单元格中重新排列值

如何在 iOS Swift 中的 didselect 方法中重新排列单元格?

使用核心数据重新排列TableView单元格的顺序

如何重新排列DateTime对象的顺序

UITableView在加载后按编号重新排列单元格

如何在Excel,R中基于部分字符串匹配重新排列行中的单元格

如何重新排列javascript数组中的对象?

根据位置重新排列单元格内容

在 ruby 中,如何重新排列具有 id 键的对象数组,将数组的新顺序作为数组?

更改行的排序顺序后如何重新排列“排序顺序”列

如何根据其内容为每一行重新排列每个单元格?

使用可变字段重新排列 Excel/R 中的多个单元格内容

如何重新排列列表中的对象

在Swift 4中对单元格重新排序后如何保存tableView顺序

Matlab,随机更改单元格数组中的顺序

如何按特定顺序重新排列Numpy数组?

如何根据对象的属性在Kotlin中重新排列ArrayList的顺序?

如何重新排列数组

NSArrayController自动重新排列对象后如何发送消息?

重新排列单元阵列中的单元

使用熊猫重新排列具有相同列标题的数据框单元格

从单元格中提取列标题并相应地重新排列列

Swift 3-重新排列并在表格视图中保留单元格

在表格视图中删除或重新排列单元格时的动画

如何重新排列评论的顺序?

如何重新排列QTableView的列顺序

AngularJS $ scope数组对象重新排列

如何在 TypeScript 中重新排列数组