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

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

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

- (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

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

#1楼 票数:5 已采纳

那么最简单的解决方案就是

  1. Target实体添加一个属性,比如Integer32类型的order

创建和插入新对象

  1. 无论何时创建新的Target对象,首先使用具有键@"order"ascending=YES sortDescriptor从数据库中获取现有对象。 获取此获取数组的最后一个对象并检查其顺序。 现在,在新的Target对象中递增顺序并将其插入数据库。 如果fetched数组返回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循环并更新其顺序。 您只需要更新两个indexPath之间的对象order

     - (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]; } 

注意 :上述解决方案假设您从0开始order


在创建和插入新的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];
}

#2楼 票数:1

简单的解决方案: Reffer Apple的Doc

创建NSMutableArray以标识重新排序的数组。

步骤1:在头文件或类文件中声明NSMutableArray属性@property (strong, nonatomic) NSMutableArray *arrayTag

第2步:viewDidLoad初始化

第3步:tableview委托方法中添加此代码

-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
    NSString *stringToMove = [arrayTag objectAtIndex:sourceIndexPath.row];
    [arrayTag removeObjectAtIndex:sourceIndexPath.row];
    [arrayTag insertObject:stringToMove atIndex:destinationIndexPath.row];
}

#3楼 票数:1

尝试这个

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

    NSString *str1 =  [[yourArray  objectAtIndex:fromIndexPath.row] copy];
    NSString *str2 =  [[yourArray  objectAtIndex:toIndexPath.row] copy];

    [yourArray replaceObjectAtIndex:fromIndexPath.row withObject:str2];
    [yourArray replaceObjectAtIndex:toIndexPath.row withObject:str1];

    [tableView reloadData];
}

#4楼 票数:1

如果我正确理解您的Q,您必须更改模型的架构。

A.首先,我明白了

你有一个项目列表。 最后添加新项目。 现在,您希望为用户提供以自定义方式重新排序项目的功能。

B.你做了什么

实际上,您正在使用创建日期属性进行排序。 当然你不能用它来重新排序,因为这意味着要改变创建日期。 因此,使用创建日期的整个方法都会失败:对于未由用户更改的列表,如果您有自定义订单,则不够。

C.你能做什么

如果您有自定义订单,则需要自定义属性来反映订单。 如果列表是实例对象的属性,则可以使用NSOrderedSet和Core Data的有序关系来执行此操作。 我不会因为付出代价。 但是,如果适合您,您可以这样做。

否则你必须自己处理:

一种。 将属性order添加到实体类型。

插入新对象时,请检查现有列表的计数(取决于您如何保存它),并将该值设置为新实例的order属性。

C。 获取时,使用该属性进行排序。

d。 更改时,更改实例对象的属性以及源和目标之间的所有实例对象的属性。 让我解释一下:

我们有这样的谎言:

name          order
Amin          0
Negm          1
Awad          2
Answer        3

现在,例如,Answer从位置3 向上移动到位置1(在Negm之前):

name          order
Amin          0
Answer        3
Negm          1
Awad          2

这意味着必须将移动的对象(3)的顺序属性改变为新的目的地(1),并且必须将具有> = 1到<3的顺序属性的所有对象改变为+1。 (显然,移动对象的顺序属性)

name          order
Amin          0
Answer        1
Negm          2
Awad          3

在代码中

NSUInteger oldIndex = …; // 3
NSUInteger newIndex = …; // 1

movedObject.order = newIndex;

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Target"];
NSPredicate *betweenPredicate = [NSPredicate predicateWithFormat:@"order >= %ld AND order < %ld", newIndex, oldIndex];
NSArray *objectsToChange = [context executeFetchRequest:request error:NULL];

for( Target *target in objectsToChange )
{
  target.order = @([target.order unsignedIntegerValue] + 1);
}

如果项目向下移动,则必须以相反的方式执行相同操作。


如果您在iTunes中有不同的唯一对象列表(如播放列表),则需要额外的实体类型而不是额外的属性。 让我知道,我将从我的一本书中发布代码,包括移动一个有缺口的项目列表。

#5楼 票数:0

如果希望NSFetchResultsController获取更改,则必须更改基础数据模型以反映新订单。

  ask by nick shmick translate from so

未解决问题?本站智能推荐:

1回复

NSFetchedResultsController无法将对象正确插入UITableView

我正在使用带有NSFetchedResultsController的UITableView。 提取具有一些谓词,并且一切正常。 所有对象都有一个索引,应以此索引对它们进行排序。 当我插入一个对象时,该索引的设置正确,但是有时该对象出现在错误的索引路径中。 但是,当我离开视图控制器并返回时
1回复

通过NSFetchedResultsController在UITableView中显示重复的单元格?

我正在查询核心数据,以在一群人中找到“最老的”和“最沉重的”。 对于较大的数据集,这通常可以工作(因为重复匹配的机会较小),但是对于较小的数据集,其中最老的人可能也是最重的人,我遇到了问题。 当我想显示在2此信息UITableViewCell一个第UITableView ,我先运行2个
2回复

更改为NSFetchedResultsController后,UITableView不更新DataSource

我有一个由NSFetchedResultsController填充的UITableView 。 初始提取工作正常。 我可以添加,删除,修改等零问题。但我想在表中添加用户定义的排序。 我这样做是通过更改NSFetchedResultsController以使用不同的sortDescripto
1回复

获取与NSFetchedResultsController有关系的对象

这是我的问题: 我有2个实体: Session (日期,字符串名称,NSSet行为) Behaviour (字符串类别,字符串时间,字符串名称,NSManagedobject会话)。 他们是一对多的关系。 在SessioneViewController ,我
1回复

在核心数据中更改托管对象模型的属性值时崩溃

我有一个表视图控制器,它使用获取的结果控制器为每一行获取项目。 当选择一行时,它将推送一个新的视图控制器来编辑该特定的受管对象模型-当我编辑并尝试保存时,我得到以下内容。 原因是什么? 谢谢 。
1回复

使用NSFetchedResultsController时如何在每节中获取一条记录

我在使用Core Data的iOS应用程序上工作,我想使用UITableView显示实体。 为此,我正在使用NSFetchedResultsController。 我要实现的目的是在其部分中显示每个记录。 基本上我想每节1行。 我正在努力的方法是: 和 因为在计算
2回复

设置新谓词后,NSFetchedResultsController无法正确刷新

我的fetchedResultsController最初是这样创建的(在viewDidLoad中): 效果很好,结果显示在我的表格视图中。 但是,当按下某些按钮时,我想过滤结果。 所以我这样做: 问题在于表视图不会重新加载。 如果滚动表格视图,则单元格将基于新数据而更改,但
2回复

如何在NSFetchedResultsController的部分中添加其他信息

我在UITableView有一个自定义部分,它有一个UIImageView和一个UILabel 。 使用NSFetchedResultsController我可以根据剖面模型设置图像。 假设剖面模型有imageName和sectionTitle 。 根据当前的实现,我将<NSFetc