如何更改将我的对象保存到对象的不同索引的NSFetchResultController数组? [英] How do I change NSFetchResultController array that holds my objects to different indexes for my objects?

查看:64
本文介绍了如何更改将我的对象保存到对象的不同索引的NSFetchResultController数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一种方法可以用来将表格视图中的单元格保存并移动到其他索引,如下所示:

I have a method that I use to hold and move cells in my table view to different index that looks like this:

- (void)moveTableView:(FMMoveTableView *)tableView moveRowFromIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { 
NSArray *allObjects = [self.fetchedResultController fetchedObjects];
//array to hold the new order    
NSMutableArray * arrayCorectOrder = [NSMutableArray new];
//the target object that is in the index we are moving from
Target *target = [self.fetchedResultController objectAtIndexPath:fromIndexPath];
 }

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

i have a coreDataStack class that takes care of all the core data stuff (creating a singelton), it looks like this:

#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

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

and whenever i add new object to core data i do it this way:

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

}

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

in the table view when I'm fetching the data i do it this way:

- (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请求配置:

this is my fetchresultconroller/fetch request config in the table view controller class:

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

}

现在我要检查订单是否已更改,因此我需要在数据库中更改订单...

and now I wand to check if the order was changed so I need to change the order in the database...

我该怎么做?

谢谢!

推荐答案

根据我的评论,提取的结果控制器将每个对象的indexPath基于基础提取的排序顺序-在您的情况下为 time .如果希望用户能够覆盖此设置并重新排列行,则将FRC更改为使用其他排序顺序.将一个新的(日期类型的)属性添加到您的实体中,命名为 sortTime ,并修改 targetsFetchRequest 方法以使用 sortTime 作为排序键.

As per my comments, the fetched results controller bases the indexPath for each object on the sort order of the underlying fetch - in your case time. If you want the user to be able to override this, and reorder the rows, then change the FRC to use a different sort order. Add a new attribute (of date type) to your entity, named sortTime, and amend the targetsFetchRequest method to use sortTime as the sort key.

无论何时添加新的 Target ,都应同时设置 sortTime .在对行进行重新排序时,请设置 sortTime 的值,以确保FRC将目标放置在新的indexPath上.像这样:

Whenever you add a new Target, set the sortTime at the same time. When it comes to reordering the rows, set the value of sortTime to ensure that the FRC places the Target at the new indexPath. Something like this:

-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
    Target *targetToMove = [self.fetchedResultsController objectAtIndexPath:sourceIndexPath];
    if (destinationIndexPath.row == 0) {
        // to move to row 0, the new sortTime can be any value
        // that is  less than the sortTime of the Target currently at
        // row 0
        Target *targetAtRow0 = [self.fetchedResultsController objectAtIndexPath:destinationIndexPath];
        targetToMove.sortTime = [targetAtRow0.sortTime dateByAddingTimeInterval:-1];
    } else {
        // for any other row, set the sortTime to be half way 
        // between the sortTime for the row before the new position
        // and the sortTime for the row at the new position
        Target *targetBefore = [self.fetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForRow:(destinationIndexPath.row-1) inSection:destinationIndexPath.section]];
        Target *targetAfter = [self.fetchedResultsController objectAtIndexPath:destinationIndexPath];
        double lowerTimeInterval = [targetBefore.sortTime timeIntervalSinceReferenceDate];
        double upperTimeInterval = [targetAfter.sortTime timeIntervalSinceReferenceDate];
        double newInterval = (lowerTimeInterval + upperTimeInterval)/2;
        NSDate *newSortTime = [NSDate dateWithTimeIntervalSinceReferenceDate:newInterval];
        targetToMove.sortTime = newSortTime;
    }
    NSError *error;
    if (![self.managedObjectContext save:&error]) {
        NSLog(@"SaveContext: error %@, %@", error, [error userInfo]);
        abort();
    }
}

这应该触发您的FRC委托方法来执行必要的表视图更新.

This should trigger your FRC delegate methods to perform the necessary table view updates.

这篇关于如何更改将我的对象保存到对象的不同索引的NSFetchResultController数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆