2013-12-12 6 views
16

मैं संग्रह दृश्य कंट्रोलर में NSFetchedResultsControllerRelegate का उपयोग करना चाहता हूं। इसलिए मैंने संग्रह दृश्य के लिए TableViewController के लिए विधि को अभी बदल दिया है।संग्रह दृश्य के लिए NSFetchedResultsContollerDelegate

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

    switch(type) { 
     case NSFetchedResultsChangeInsert: 
      [self.collectionView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]]; 
      break; 

     case NSFetchedResultsChangeDelete: 
      [self.collectionView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] ]; 

     break; 
    } 
} 


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

    UICollectionView *collectionView = self.collectionView; 

    switch(type) { 

    case NSFetchedResultsChangeInsert: 
     [collectionView insertItemsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]]; 
     break; 

    case NSFetchedResultsChangeDelete: 
     [collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]]; 
     break; 

    case NSFetchedResultsChangeUpdate: 
     [collectionView reloadItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]]; 
     break; 

    case NSFetchedResultsChangeMove: 
     [collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]]; 
     [collectionView insertItemsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]]; 
     break; 
    } 
} 

(void)controllerDidChangeContent:(NSFetchedResultsController *)controller { 
    [self.collectionView reloadData]; 
} 

लेकिन मैं एक CollectionView के लिए (TableVie w के लिए endUpdates) WillChangeContent (beginUpdatesTableView के लिए) और DidChangeContent को संभालने के लिए कैसे पता नहीं है।

सबकुछ ठीक काम करता है सिवाय इसके कि जब मैं एक आइटम को एक सेक्शन में दूसरे अनुभाग में ले जाता हूं। तब मुझे निम्न त्रुटि मिलती है।

यह आमतौर पर NSManagedObjectContextObjectsDidChangeNotification के पर्यवेक्षक के भीतर एक बग है। अमान्य अद्यतन: खंड 0 में आइटमों की अवैध संख्या ....

कोई विचार मैं इस समस्या को कैसे हल कर सकता हूं?

उत्तर

10

संग्रह दृश्य के साथ एक प्राप्त परिणाम नियंत्रक को जोड़ना थोड़ा मुश्किल है। समस्या

से समझाया गया है आप कैसे NSInternalInconsistencyException क्रम अपवाद के आसपास UICollectionView साथ पाने के लिए देख रहे हैं, मैं का ब्यौरा कैसे क़तार में GitHub पर एक उदाहरण है NS12etchedResultsControllerDelegate से अपडेट।

समस्या यह है कि मौजूदा UITableView वर्ग beginUpdates और endUpdates का उपयोग करता तालिका दृश्य करने के लिए बैच प्रस्तुत करने के लिए है। UICollectionView में एक नया performBatchUpdates: विधि है, जो संग्रह दृश्य को अद्यतन करने के लिए ब्लॉक पैरामीटर लेता है। यह सेक्सी है, लेकिन यह NS12etchedResultsController के मौजूदा प्रतिमान के साथ अच्छी तरह से काम नहीं करता है।

README से::

यह कैसे नए UICollectionView उपयोग करने के लिए का एक उदाहरण है

सौभाग्य से, कि लेख में यह भी एक नमूना कार्यान्वयन प्रदान करता है NSFetchedResultsController के साथ। चाल NSFetchedResultsControllerDelegate के माध्यम से नियंत्रक समाप्त होने तक अपडेट को कतारबद्ध करने के लिए है। UICollectionView ही beginUpdates और endUpdatesUITableView यह आसानी से NSFetchedResultsController साथ काम नहीं है नहीं है, ताकि आप उन्हें कतार में है या आप आंतरिक स्थिरता क्रम अपवाद मिलता है।

+0

धन्यवाद, मार्टिन। मैंने पहले बिना काम के इस कोशिश की - कामकाज के लिए अद्यतन नहीं देखा। अब संग्रह में बग के कामकाज के साथ यह अंततः काम करता है। इस तथ्य के कारण कि मेरे पास हेडर और पाद लेख हैं, यह बहुत अच्छी मदद थी। मुझे आशा है कि फिर भी यह बग एक बार हल हो जाएगा। – aquarius68

+0

@ Aquarius68: यह वास्तव में एक बग नहीं है। समस्या यह है कि एफआरसी प्रतिनिधि विधियों और संग्रह दृश्य अद्यतन विधियां वास्तव में एक साथ फिट नहीं होती हैं। फिक्स्डिंग का मतलब एपीआई में से किसी एक को बदलना या विस्तार करना है। - लेकिन मुझे खुशी है कि आप इसे काम कर रहे हैं। –

+0

मुझे अब और त्रुटि संदेश नहीं मिलते हैं लेकिन यह अभी तक पूरी तरह से काम नहीं करता है; यानी यदि उपयोगकर्ता पहला तत्व जोड़ता है तो यह काम करता है, लेकिन यदि उपयोगकर्ता दूसरा तत्व जोड़ता है तो यह केवल तभी काम करता है जब मैं तालिका दृश्य पर वापस जाता हूं जिसमें संग्रह दृश्य की वस्तुओं से संबंधित वस्तुएं होती हैं। – aquarius68

27

यहां स्विफ्ट के साथ मेरा कार्यान्वयन है।

var blockOperations: [NSBlockOperation] = [] 

नियंत्रक में, फिर से init बदल जाएगा सरणी:

func controllerWillChangeContent(controller: NSFetchedResultsController) { 
    blockOperations.removeAll(keepCapacity: false) 
} 

किया परिवर्तन वस्तु विधि में:

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { 

    if type == NSFetchedResultsChangeType.Insert { 
     println("Insert Object: \(newIndexPath)") 

     blockOperations.append(
      NSBlockOperation(block: { [weak self] in 
       if let this = self { 
        this.collectionView!.insertItemsAtIndexPaths([newIndexPath!]) 
       } 
      }) 
     ) 
    } 
    else if type == NSFetchedResultsChangeType.Update { 
     println("Update Object: \(indexPath)") 
     blockOperations.append(
      NSBlockOperation(block: { [weak self] in 
       if let this = self { 
        this.collectionView!.reloadItemsAtIndexPaths([indexPath!]) 
       } 
      }) 
     ) 
    } 
    else if type == NSFetchedResultsChangeType.Move { 
     println("Move Object: \(indexPath)") 

     blockOperations.append(
      NSBlockOperation(block: { [weak self] in 
       if let this = self { 
        this.collectionView!.moveItemAtIndexPath(indexPath!, toIndexPath: newIndexPath!) 
       } 
      }) 
     ) 
    } 
    else if type == NSFetchedResultsChangeType.Delete { 
     println("Delete Object: \(indexPath)") 

     blockOperations.append(
      NSBlockOperation(block: { [weak self] in 
       if let this = self { 
        this.collectionView!.deleteItemsAtIndexPaths([indexPath!]) 
       } 
      }) 
     ) 
    } 
} 

किया में पहले NSBlockOperations की एक सरणी आरंभ अनुभाग विधि बदलें:

func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) { 

    if type == NSFetchedResultsChangeType.Insert { 
     println("Insert Section: \(sectionIndex)") 

     blockOperations.append(
      NSBlockOperation(block: { [weak self] in 
       if let this = self { 
        this.collectionView!.insertSections(NSIndexSet(index: sectionIndex)) 
       } 
      }) 
     ) 
    } 
    else if type == NSFetchedResultsChangeType.Update { 
     println("Update Section: \(sectionIndex)") 
     blockOperations.append(
      NSBlockOperation(block: { [weak self] in 
       if let this = self { 
        this.collectionView!.reloadSections(NSIndexSet(index: sectionIndex)) 
       } 
      }) 
     ) 
    } 
    else if type == NSFetchedResultsChangeType.Delete { 
     println("Delete Section: \(sectionIndex)") 

     blockOperations.append(
      NSBlockOperation(block: { [weak self] in 
       if let this = self { 
        this.collectionView!.deleteSections(NSIndexSet(index: sectionIndex)) 
       } 
      }) 
     ) 
    } 
} 

और अंत में, किया नियंत्रक में सामग्री विधि बदल दिया:

:

func controllerDidChangeContent(controller: NSFetchedResultsController) {   
    collectionView!.performBatchUpdates({() -> Void in 
     for operation: NSBlockOperation in self.blockOperations { 
      operation.start() 
     } 
    }, completion: { (finished) -> Void in 
     self.blockOperations.removeAll(keepCapacity: false) 
    }) 
} 

मैं व्यक्तिगत रूप से और साथ ही deinit विधि में कुछ कोड जोड़ा आदेश कार्यवाही रद्द करना जब ViewController के बारे में पुनः आवंटित की जाती पाने के लिए है में,

deinit { 
    // Cancel all block operations when VC deallocates 
    for operation: NSBlockOperation in blockOperations { 
     operation.cancel() 
    } 

    blockOperations.removeAll(keepCapacity: false) 
} 
+0

यह खूबसूरती से काम करता है, "प्लॉट"! धन्यवाद! –

+0

कोई '.Move' अनुभागों के लिए परिवर्तन प्रकार? – pkamb

+0

@pkamb 'UICollectionView' में सेक्शन के लिए कोई" चाल "नहीं है। – Fogmeister

1

यहाँ स्विफ्ट का एक सा है कि UICollectionViewController के installsStandardGestureForInteractiveMovement साथ काम करता है और है कुछ हद तक एक अप dryed और installsStandardGestureForInteractiveMovement पर स्विच ताकि सभी कोड पथ स्पष्ट कर रहे हैं। यह प्लॉट कोड के समान समग्र पैटर्न है।

var fetchedResultsProcessingOperations: [NSBlockOperation] = [] 

private func addFetchedResultsProcessingBlock(processingBlock:(Void)->Void) { 
    fetchedResultsProcessingOperations.append(NSBlockOperation(block: processingBlock)) 
} 

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { 

    switch type { 
    case .Insert: 
     addFetchedResultsProcessingBlock {self.collectionView!.insertItemsAtIndexPaths([newIndexPath!])} 
    case .Update: 
     addFetchedResultsProcessingBlock {self.collectionView!.reloadItemsAtIndexPaths([indexPath!])} 
    case .Move: 
     addFetchedResultsProcessingBlock { 
      // If installsStandardGestureForInteractiveMovement is on 
      // the UICollectionViewController will handle this on its own. 
      guard !self.installsStandardGestureForInteractiveMovement else { 
       return 
      } 
      self.collectionView!.moveItemAtIndexPath(indexPath!, toIndexPath: newIndexPath!) 
     } 
    case .Delete: 
     addFetchedResultsProcessingBlock {self.collectionView!.deleteItemsAtIndexPaths([indexPath!])} 
    } 

} 

func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) { 

    switch type { 
    case .Insert: 
     addFetchedResultsProcessingBlock {self.collectionView!.insertSections(NSIndexSet(index: sectionIndex))} 
    case .Update: 
     addFetchedResultsProcessingBlock {self.collectionView!.reloadSections(NSIndexSet(index: sectionIndex))} 
    case .Delete: 
     addFetchedResultsProcessingBlock {self.collectionView!.deleteSections(NSIndexSet(index: sectionIndex))} 
    case .Move: 
     // Not something I'm worrying about right now. 
     break 
    } 

} 

func controllerDidChangeContent(controller: NSFetchedResultsController) { 
    collectionView!.performBatchUpdates({() -> Void in 
     for operation in self.fetchedResultsProcessingOperations { 
      operation.start() 
     } 
     }, completion: { (finished) -> Void in 
      self.fetchedResultsProcessingOperations.removeAll(keepCapacity: false) 
    }) 
} 

deinit { 
    for operation in fetchedResultsProcessingOperations { 
     operation.cancel() 
    } 

    fetchedResultsProcessingOperations.removeAll() 
} 
9

मैं बना @ प्लॉट के समाधान यह खुद वस्तु है और यह करने के लिए परिवर्तित स्विफ्ट 2

import Foundation 
import CoreData 

class CollectionViewFetchedResultsControllerDelegate: NSObject, NSFetchedResultsControllerDelegate { 

    // MARK: Properties 

    private let collectionView: UICollectionView 
    private var blockOperations: [NSBlockOperation] = [] 

    // MARK: Init 

    init(collectionView: UICollectionView) { 
     self.collectionView = collectionView 
    } 

    // MARK: Deinit 

    deinit { 
     blockOperations.forEach { $0.cancel() } 
     blockOperations.removeAll(keepCapacity: false) 
    } 

    // MARK: NSFetchedResultsControllerDelegate 

    func controllerWillChangeContent(controller: NSFetchedResultsController) { 
     blockOperations.removeAll(keepCapacity: false) 
    } 

    func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { 

     switch type { 

     case .Insert: 
      guard let newIndexPath = newIndexPath else { return } 
      let op = NSBlockOperation { [weak self] in self?.collectionView.insertItemsAtIndexPaths([newIndexPath]) } 
      blockOperations.append(op) 

     case .Update: 
      guard let newIndexPath = newIndexPath else { return } 
      let op = NSBlockOperation { [weak self] in self?.collectionView.reloadItemsAtIndexPaths([newIndexPath]) } 
      blockOperations.append(op) 

     case .Move: 
      guard let indexPath = indexPath else { return } 
      guard let newIndexPath = newIndexPath else { return } 
      let op = NSBlockOperation { [weak self] in self?.collectionView.moveItemAtIndexPath(indexPath, toIndexPath: newIndexPath) } 
      blockOperations.append(op) 

     case .Delete: 
      guard let indexPath = indexPath else { return } 
      let op = NSBlockOperation { [weak self] in self?.collectionView.deleteItemsAtIndexPaths([indexPath]) } 
      blockOperations.append(op) 

     } 
    } 

    func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) { 

     switch type { 

     case .Insert: 
      let op = NSBlockOperation { [weak self] in self?.collectionView.insertSections(NSIndexSet(index: sectionIndex)) } 
      blockOperations.append(op) 

     case .Update: 
      let op = NSBlockOperation { [weak self] in self?.collectionView.reloadSections(NSIndexSet(index: sectionIndex)) } 
      blockOperations.append(op) 

     case .Delete: 
      let op = NSBlockOperation { [weak self] in self?.collectionView.deleteSections(NSIndexSet(index: sectionIndex)) } 
      blockOperations.append(op) 

     default: break 

     } 
    } 

    func controllerDidChangeContent(controller: NSFetchedResultsController) { 
     collectionView.performBatchUpdates({ 
      self.blockOperations.forEach { $0.start() } 
     }, completion: { finished in 
      self.blockOperations.removeAll(keepCapacity: false) 
     }) 
    } 

} 

उपयोग:

fetchedResultsController.delegate = CollectionViewFetchedResultsControllerDelegate(collectionView) 
संबंधित मुद्दे