2

我一直在閱讀關於UISearchDisplayController及其delegate的所有文檔,但是當搜索條件發生變化時,我無法找到任何使表格視圖動畫的方法。UISearchDisplayController animate reloadData

我使用這兩種方法: UISearchDisplayController methods

他們都返回YES但仍無法找到任何方式做類似的東西: UITableView Methods

我不知道這是否是重要的但我使用的是NSfetchedResultsController來填充UITableView中的UISearchDisplayController

這就是它,謝謝!

+0

在委託方法中,您將新謂詞分配給fetchresultscontroller。搜索完成後,您將謂詞分配給原始。網上有一些有用的教程,谷歌。 – Shmidt 2013-02-10 12:28:30

+0

我試圖改變fetchrequest謂詞,但似乎並沒有觸發NSFetchedResultsController的contentDidChange方法 – ItsASecret 2013-02-10 16:03:39

+0

您是否在運行fetchedResultsController之後執行了-performFetchRequest? – Shmidt 2013-02-10 16:26:23

回答

8

當搜索字符串或範圍發生變化時,您爲獲取的結果控制器分配新的獲取請求,因此必須調用performFetch以獲取新的結果集。 performFetch重置控制器的狀態,並且不會觸發任何FRC委託方法。

因此,在更改提取請求後,必須「手動」更新表視圖。在大多數示例程序,這是由

  • 呼籲reloadData上的搜索表視圖,或
  • 返回YESshouldReloadTableForSearchStringshouldReloadTableForSearchScope完成。

效果是一樣的:搜索表視圖重新加載沒有動畫。

我不認爲有任何內置/簡單的方法來動畫表視圖更新時,搜索謂詞更改。但是,你可以試試下面的(這只是一個想法,我其實沒有這個嘗試我自己):

  • 之前改變讀取請求,使舊的結果集的副本:

    NSArray *oldList = [[fetchedResultsController fetchedObjects] copy]; 
    
  • 將新獲取請求分配給FRC並呼叫performFetch

  • 獲取新的結果集:

    NSArray *newList = [fetchedResultsController fetchedObjects]; 
    
  • 不要叫上搜索表視圖reloadData

  • 比較oldListnewList檢測新的和刪除的對象。爲新對象調用insertRowsAtIndexPaths,爲已刪除對象調用deleteRowsAtIndexPaths。這可以通過並行遍歷兩個列表來完成。
  • 返回NOshouldReloadTableForSearchStringshouldReloadTableForSearchScope

正如我所說,這只是一個想法,但我認爲它可以工作。

+0

問題非常感謝您抽出這麼多的時間來幫助我和你的好答案:)我是那種不希望我不得不做這樣的事情,但仍然是一個工作解決方案非常感謝你=) – ItsASecret 2013-02-10 20:08:29

1

我知道這個問題已經過時了,但是我最近遇到了這個問題,並且希望有一個解決方案,無論NSFetchedResultsController是如何初始化的都可以工作。它基於@ martin-r的回答。

這裏的相應的要旨:https://gist.github.com/stephanecopin/4ad7ed723f9857d96a777d0e7b45d676

import CoreData 

extension NSFetchedResultsController { 
    var predicate: NSPredicate? { 
     get { 
      return self.fetchRequest.predicate 
     } 
     set { 
      try! self.setPredicate(newValue) 
     } 
    } 

    var sortDescriptors: [NSSortDescriptor]? { 
     get { 
      return self.fetchRequest.sortDescriptors 
     } 
     set { 
      try! self.setSortDescriptors(newValue) 
     } 
    } 

    func setPredicate(predicate: NSPredicate?) throws { 
     try self.setPredicate(predicate, sortDescriptors: self.sortDescriptors) 
    } 

    func setSortDescriptors(sortDescriptors: [NSSortDescriptor]?) throws { 
     try self.setPredicate(self.predicate, sortDescriptors: sortDescriptors) 
    } 

    func setPredicate(predicate: NSPredicate?, sortDescriptors: [NSSortDescriptor]?) throws { 
     func updateProperties() throws { 
      if let cacheName = cacheName { 
       NSFetchedResultsController.deleteCacheWithName(cacheName) 
      } 

      self.fetchRequest.predicate = predicate 
      self.fetchRequest.sortDescriptors = sortDescriptors 
      try self.performFetch() 
     } 

     guard let delegate = self.delegate else { 
      try updateProperties() 
      return 
     } 

     let previousSections = self.sections ?? [] 
     let previousSectionsCount = previousSections.count 
     var previousObjects = Set(self.fetchedObjects as? [NSManagedObject] ?? []) 
     var previousIndexPaths: [NSManagedObject: NSIndexPath] = [:] 
     previousObjects.forEach { 
      previousIndexPaths[$0] = self.indexPathForObject($0) 
     } 
     try updateProperties() 
     let newSections = self.sections ?? [] 
     let newSectionsCount = newSections.count 
     var newObjects = Set(self.fetchedObjects as? [NSManagedObject] ?? []) 
     var newIndexPaths: [NSManagedObject: NSIndexPath] = [:] 
     newObjects.forEach { 
      newIndexPaths[$0] = self.indexPathForObject($0) 
     } 

     let updatedObjects = newObjects.intersect(previousObjects) 
     previousObjects.subtractInPlace(updatedObjects) 
     newObjects.subtractInPlace(updatedObjects) 

     var moves: [(object: NSManagedObject, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath)] = [] 
     updatedObjects.forEach { updatedObject in 
      if let previousIndexPath = previousIndexPaths[updatedObject], 
       let newIndexPath = newIndexPaths[updatedObject] 
      { 
       if previousIndexPath != newIndexPath { 
        moves.append((updatedObject, previousIndexPath, newIndexPath)) 
       } 
      } 
     } 

     if moves.isEmpty && previousObjects.isEmpty && newObjects.isEmpty { 
      // Nothing really changed 
      return 
     } 

     delegate.controllerWillChangeContent?(self) 

     moves.forEach { 
      delegate.controller?(self, didChangeObject: $0.object, atIndexPath: $0.fromIndexPath, forChangeType: .Move, newIndexPath: $0.toIndexPath) 
     } 

     let sectionDifference = newSectionsCount - previousSectionsCount 
     if sectionDifference < 0 { 
      (newSectionsCount..<previousSectionsCount).forEach { 
       delegate.controller?(self, didChangeSection: previousSections[$0], atIndex: $0, forChangeType: .Delete) 
      } 
     } else if sectionDifference > 0 { 
      (previousSectionsCount..<newSectionsCount).forEach { 
       delegate.controller?(self, didChangeSection: newSections[$0], atIndex: $0, forChangeType: .Insert) 
      } 
     } 

     previousObjects.forEach { 
      delegate.controller?(self, didChangeObject: $0, atIndexPath: previousIndexPaths[$0], forChangeType: .Delete, newIndexPath: nil) 
     } 
     newObjects.forEach { 
      delegate.controller?(self, didChangeObject: $0, atIndexPath: nil, forChangeType: .Insert, newIndexPath: newIndexPaths[$0]) 
     } 

     delegate.controllerDidChangeContent?(self) 
    } 
} 

它暴露在NSFetchedResultsControllerpredicatesortDescriptors這反映那些在fetchRequest找到2個特性。
當這些屬性中的任何一個被設置時,控制器將自動計算更改並通過委託發送它們,所以希望沒有主要的代碼更改。 如果你不想動畫,你仍然可以直接在fetchRequest本身上設置predicatesortDescriptors