0

ここで私のジレンマを再確認するには、NSFetchedResultsControllerを使用するようにコードをリファクタリングしています。行があるかどうかにかかわらず、いつも表示したい5つのセクションのセットです。私はそれらを表示することにいくらか成功していますが、残念ながら正しいセクションの下に表示される適切な行を得ることができません。 (注:カスタムヘッダーを使用して、ユーザーが特定のセクションにセルを追加するたびに行を追加するボタンを使用しています)。coreDataのモデル関係は、Dogモデルが多くのタスクを持つことができますが、一匹の犬。残念なことに、私は作成したすべてのユニークな "Dog"のすべてのタスクをフェッチしているように見えます。そのため、すべてが同じ情報を持っています。NSFetchedResultsControllerを使用する方法5セクションを表示して適切な行を取得するためにフィルタリングする方法はありますか

NSFetchedResultsControllerに5つのセクションを作成するために使用するタスクモデルと列挙型は次のとおりです。

import Foundation 
import CoreData 

enum Type: String { 
    case Meals = "Meals" 
    case Exercise = "Exercise" 
    case Health = "Health" 
    case Training = "Training" 
    case Misc = "Misc" 
} 


class Task: NSManagedObject { 
    static let kClassName = "Task" 

    convenience init?(title: String, type: Type, isComplete: Bool, context: NSManagedObjectContext = Stack.sharedStack.managedObjectContext) { 
     guard let entity = NSEntityDescription.entityForName(Task.kClassName, inManagedObjectContext: context) else { return nil } 

     self.init(entity: entity, insertIntoManagedObjectContext: context) 
     self.title = title 
     self.isChecked = isComplete 
     self.type = type.rawValue 
    } 
} 

ここに私のsectionNameKeyPathとしてEnum Typeを渡しているFetchedResultsControllerがあります。 numberOfRowsInSectionで

class TaskController { 
    static let sharedController = TaskController() 
    private let kTask = "Task" 
    var fetchedResultsController: NSFetchedResultsController 

    var dog: Dog? 

    init() { 
     let request = NSFetchRequest(entityName: kTask) 
     let sortDescriptor1 = NSSortDescriptor(key: "type", ascending: true) 
     request.sortDescriptors = [sortDescriptor1] 

     fetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: Stack.sharedStack.managedObjectContext, sectionNameKeyPath: String(Type), cacheName: nil) 
     _ = try? fetchedResultsController.performFetch() 
    } 
} 

Iは、行が最初に作成されるまでfetchedResultsController部が実際には存在しないと仮定していたように、私は機能性部と等しくなるようにsections.countと一致しようとしていますか?正直言って、この時点では、適切なセクションに一致する正しい行をフェッチする方法がわからないので、私は失われています。コメントされたコードは、私がコードをリファクタリングしてNSFetchedResultsControllerの方法に更新する前に、最初に正しいセクションの正しい行を取得していた方法でした。

extension DogDetailViewController: UITableViewDataSource { 
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     guard let sections = TaskController.sharedController.fetchedResultsController.sections else { return 0 } 

     if sections.count > 0 && section < sections.count { 
      return sections[section].numberOfObjects 
     } 
     return 0 

      //   } 

      //  if let dog = self.dog { 
      //   switch section { 
      //   case 0: 
      //    return dog.tasks.filter({$0.type == String(Type.Meals)}).count 
      //   case 1: 
      //    return dog.tasks.filter({$0.type == String(Type.Exercise)}).count 
      //   case 2: 
      //    return dog.tasks.filter({$0.type == String(Type.Health)}).count 
      //   case 3: 
      //    return dog.tasks.filter({$0.type == String(Type.Training)}).count 
      //   case 4: 
      //    return dog.tasks.filter({$0.type == String(Type.Misc)}).count 
      //   default: 
      //    return 0 
      //   } 
      //  } else { 
      //   return 0 
      //  } 
     } 

ご協力ありがとうございます。

答えて

1

特定の犬に存在するタスクの数に関係なく、5つのセクションがすべて表示されるようにするには、セクション数とその順序をハードコーディングし、NSFetchedResultsController(したがって異なるNSFetchRequest )を指定します。

あなたの既存のフェッチリクエストは、特定の犬にリクエストを制限するものではありません(NSPredicateを適切な制約で作成し、フェッチリクエストで設定することでこれを行います)。これはおそらく重要ですので、すべてTaskをメモリにプルしてからフィルタを実行しないでください。これを行うには、Taskエンティティが、データモデルのDogエンティティとの関係を持っている必要があります。これは、投稿したコードに基づいて明らかではありません。私はあなたがこの関係を持っていると仮定します。 (以下のTaskDataSource)のシングルトンモデルは、現在の方法で使用することはできません。リクエストするDogを変更するたびに新しいモデルを作成する必要があります。

TaskControllerTaskDataSourceにして、UICollectionViewDataSourceというプロトコルを直接採用したことにも注意してください。これは必須ではありませんが、アプリケーションが複数の画面でこのコンテンツを必要とする可能性がある場合は、これを再利用することができます。

class TaskDataSource: NSObject, UICollectionViewDataSource { 
    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { 
     return TaskDataSource.Sections.count 
    } 

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 
     let count: Int 
     switch TaskDataSource.Sections[section] { 
     case .Meals: 
      count = mealsResultsController?.sections?.first?.numberOfObjects ?? 0 
     case .Exercise: 
      count = exerciseResultsController?.sections?.first?.numberOfObjects ?? 0 
     case .Health: 
      count = healthResultsController?.sections?.first?.numberOfObjects ?? 0 
     case .Training: 
      count = trainingResultsController?.sections?.first?.numberOfObjects ?? 0 
     case .Misc: 
      count = miscResultsController?.sections?.first?.numberOfObjects ?? 0 
     } 

     return count 
    } 

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { 
     let task: Task 
     // Each fetched results controller has a singel section, so we have to make an appropriate index path 
     let adjustedIndexPath = NSIndexPath(forItem: indexPath.item, inSection: 0) 
     switch TaskDataSource.Sections[indexPath.section] { 
     case .Meals: 
      task = mealsResultsController?.objectAtIndexPath(adjustedIndexPath) as! Task 
     case .Exercise: 
      task = exerciseResultsController?.objectAtIndexPath(adjustedIndexPath) as! Task 
     case .Health: 
      task = healthResultsController?.objectAtIndexPath(adjustedIndexPath) as! Task 
     case .Training: 
      task = trainingResultsController?.objectAtIndexPath(adjustedIndexPath) as! Task 
     case .Misc: 
      task = miscResultsController?.objectAtIndexPath(adjustedIndexPath) as! Task 
     } 

     // This part will vary, depending on your cell/storyboard, but this is the idea. Note we don't use the adjusted index path here 
     let cell = collectionView.dequeueReusableCellWithReuseIdentifier("TaskCell", forIndexPath: indexPath) as! TaskCell 
     cell.titleLabel.text = task.title 

     return cell 
    } 

    init(dog: Dog) { 
     // Create a sort descriptor to sort by whatever you like, I assume you'd want things sorted by title 
     let sortDescriptor = NSSortDescriptor(key: "title", ascending: true) 

     // A closure to create an NSFetchedResultsController, this avoids copy/pasting 
     let createFetchRequestForType = { (type: Type) -> NSFetchedResultsController? in 
      let fetchRequest = NSFetchRequest(entityName: Task.kClassName) 
      // Note, you'll want to create a multi-key index on the Task entity to make sure this is reasonably fast 
      fetchRequest.predicate = NSPredicate(format: "dog == %@ && type == %@", dog, type.rawValue) 
      fetchRequest.sortDescriptors = [sortDescriptor] 

      let context = Stack.sharedStack.managedObjectContext 
      let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil) 
      do { 
       try fetchedResultsController.performFetch() 
      } 
      catch { 
       return nil 
      } 

      return fetchedResultsController 
     } 

     mealsResultsController = createFetchRequestForType(.Meals) 
     exerciseResultsController = createFetchRequestForType(.Exercise) 
     healthResultsController = createFetchRequestForType(.Health) 
     trainingResultsController = createFetchRequestForType(.Training) 
     miscResultsController = createFetchRequestForType(.Misc) 
    } 

    static let Sections: Array<Type> = [.Meals, .Exercise, .Health, .Training, .Misc] 

    var mealsResultsController: NSFetchedResultsController? 
    var exerciseResultsController: NSFetchedResultsController? 
    var healthResultsController: NSFetchedResultsController? 
    var trainingResultsController: NSFetchedResultsController? 
    var miscResultsController: NSFetchedResultsController? 
} 
+0

@Charles A.さん、ありがとうございます。 NSFetchedResultsControllerの変数割り当てをSections配列の各項目に与えたのは面白いことです。私は単純に私が必要としていた情報を単にフィルタリングするためのNSFetchedResultsControllerを1つだけ必要とすると仮定しました。 –

+0

タスクが特定の型に対して存在しないときにセクション全体を省略したいのであれば、 'NSFetchedResultsController'を使用し、' NSPredicate'の 'type'の制約を省略し、' sectionNameKeyPath '。あなたは常にセクションを望むと考えると、これはより簡単なアプローチだと思う。理想的には、DBエンジンでのフィルタリングは、メモリではなく、そうするのが妥当であるときに述語で行いたいと思っています。 –

関連する問題