3

我有一個表視圖,並且我剛剛實現了一個類,該類幫助我重新排列單元格,就像表視圖委託中隨附的常規移動單元格方法。如何在重新排序單元格後更改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]; 

} 

表中的VIE當我獲取數據W I這樣來做:

- (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 /取表視圖控制器類的要求配置:

- (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」。所以我認識到2個單元具有相同標籤的情況。

+0

NSFetchedResultsController排序的屬性是什麼? – 2015-03-30 22:42:06

+0

只是單元格的文本@ErikJohansson – 2015-03-30 22:43:19

+0

爲什麼不根據您的條件重新排序數組,然後重新加載表以重新排列單元格? – 2015-03-31 01:28:24

回答

5

那麼最簡單的解決辦法是

  1. 添加屬性您Target實體,說它Integer32類型的order

創建並插入新的對象

  • 每當創建新Target對象,首先使用sortDescriptor具有鍵@"order"和​​從數據庫讀取現有的對象。取出這個獲取數組的最後一個對象並檢查它的順序。現在在您的新Target對象中遞增訂單並將其插入數據庫。如果獲取的數組返回0個對象,則設置爲[email protected](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

  • 取使用上述的對象定義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; 
        } 
    

    重新排列細胞

  • 現在,當重新排列在表格視圖細胞,同時,你只需要運行一個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]; 
    } 
    
  • :以上解決方案假定您有order從0


    開始當你創建你需要實現NSFetchedResultsController委託方法添加插入新Target對象這些對象的相應行。由於我們已經定義了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]; 
    } 
    
    +0

    我在理解#2時遇到了問題,您可以試着向我解釋一下嗎?非常感謝@Burhanuddin Sunelwala – 2015-04-07 21:01:26

    +0

    在你的問題結尾處,你提到_「我想要完成的是每當用戶創建一個目標對象時它將會到達數組的末尾......」,所以無論你創建一個新的Target對象,你應該知道分配給它的順序。因此,您可以獲取按其順序排序的現有「Target」對象,並檢查最後一個對象的順序。現在您知道要爲新對象設置什麼順序,即最後一個對象的順序爲+1。 – 2015-04-08 04:36:50

    +0

    **如果不刪除對象**,則只需獲取現有對象並進行計數。您可以將計數作爲訂單分配給新對象。讓我知道,如果你知道了。 – 2015-04-08 04:37:59

    0

    如果您希望NSFetchResultsController獲取更改,您必須更改基礎數據模型以反映新的順序。

    +0

    ,我該怎麼做.. – 2015-03-30 22:43:45

    +0

    如果你想繼續使用NSFetchedResultsController,你需要添加一個屬性到你的數據模型(即sortOrder),你可以更新它以反映對象應該排序的順序。取決於數據的外觀,這可能是也可能不是個好主意。 – 2015-03-30 22:46:38

    1

    簡單的解決方案:Reffer Apple's 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]; 
    } 
    
    0

    試試這個

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

    如果我理解正確的您的問與答,你必須改變模型的模式。

    A.首先,我的理解

    你有一個項目列表。最後添加新項目。現在,您要讓用戶能夠以自定義的方式對項目進行重新排序。

    B.你做

    什麼其實你正在使用排序創建日期屬性。當然,你不能用這個重新排序,因爲這意味着改變創建日期。因此,使用創建日期的整個方法都會失敗:對於未由用戶更改的列表來說,這已經足夠了,但如果您有自定義的訂單,則不會。

    C.你可以做

    如果你有一個自定義的順序,你需要一個定製的屬性,以反映訂單。如果列表是實例對象的屬性,那麼可以使用NSOrderedSet和Core Data的有序關係來完成此操作。我不會因爲收益。但是,如果適合你,你可以做到。

    否則你必須自己處理:

    a。將屬性order添加到您的實體類型。

    b。插入新對象時,請檢查現有列表的數量(取決於您如何保存它),並將該值設置爲新實例的order屬性。

    c。提取時,使用該屬性進行排序。 d)。更改時,請更改源和目​​標之間的實例對象和所有實例對象的屬性。讓我來解釋一下:

    我們有一個這樣的LIS:現在

    name   order 
    Amin   0 
    Negm   1 
    Awad   2 
    Answer  3 
    

    ,例如,接聽移動向上從位置3(Negm提前)位置1:

    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中有不同的播放列表等獨特對象列表,則需要額外的實體類型而不是額外的屬性。讓我知道,我會從我的一本書中發佈代碼,包括移動一個有缺陷的項目列表。

    相關問題