我是swift的新手。我正在使用tableviewcontroller并使用核心数据来显示我的搜索结果。搜索按钮工作正常,这是正确的但每当我点击取消按钮它显示我空屏幕。我打印了项目数量。它达到所需的计数并重置为零。我看了很多答案,但我还没有找到对我有用的东西。我正在使用自定义单元格,甚至在点击搜索后它会显示搜索字符串的结果。
class CoinViewController: UITableViewController,UISearchResultsUpdating, UISearchBarDelegate {
let searchController = UISearchController(searchResultsController: nil)
lazy var fetchedResultController: NSFetchedResultsController<NSFetchRequestResult> = {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: String(describing: Coin.self))
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "coinName", ascending: true)]
let frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: CoreDataStack.sharedInstance.persistentContainer.viewContext, sectionNameKeyPath: nil, cacheName: nil)
frc.delegate = self
return frc
}()
override func viewDidLoad() {
super.viewDidLoad()
self.getData()
self.navigationItem.title = "Coin List"
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.reloadData()
searchController.searchBar.delegate = self
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
private func createCoinEntityFrom(dictionary: [String: AnyObject]) -> NSManagedObject? {
let service = ApiService()
let context = CoreDataStack.sharedInstance.persistentContainer.viewContext
if let coinEntity = NSEntityDescription.insertNewObject(forEntityName: "Coin", into: context) as? Coin {
coinEntity.algorithm = dictionary["Algorithm"] as? String
coinEntity.coinName = dictionary["CoinName"] as? String
if let imageURL = dictionary["ImageUrl"] as? String {
coinEntity.imageURL = (service.baseImageurl) + imageURL
}
coinEntity.totalCoinSupply = dictionary["TotalCoinSupply"] as? String
return coinEntity
}
return nil
}
private func saveInCoreDataWith(array: [String: AnyObject]) {
_ = array.map{self.createCoinEntityFrom(dictionary: $1 as! [String : AnyObject])}
do {
try CoreDataStack.sharedInstance.persistentContainer.viewContext.save()
} catch let error {
print(error)
}
}
private func clearData() {
do {
let context = CoreDataStack.sharedInstance.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: String(describing: Coin.self))
do {
let objects = try context.fetch(fetchRequest) as? [NSManagedObject]
_ = objects.map{$0.map{context.delete($0)}}
CoreDataStack.sharedInstance.saveContext()
} catch let error {
print("ERROR DELETING : \(error)")
}
}
}
func showAlertWith(title: String, message: String, style: UIAlertControllerStyle = .alert) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: style)
let action = UIAlertAction(title: title, style: .default) { (action) in
self.dismiss(animated: true, completion: nil)
}
alertController.addAction(action)
self.present(alertController, animated: true, completion: nil)
}
func getData() {
do {
try self.fetchedResultController.performFetch()
print("COUNT FETCHED FIRST: \(self.fetchedResultController.sections?[0].numberOfObjects)")
} catch let error {
print("ERROR: \(error)")
}
let service = ApiService()
service.getDataWith { (result) in
switch result {
case .Success(let data):
// for item in data {
// self.coin.append(item as! Coin)
// }
self.clearData()
self.saveInCoreDataWith(array: data)
case .Error(let message):
DispatchQueue.main.async {
self.showAlertWith(title: "Error", message: message)
}
}
}
}
func updateSearchResults(for searchController: UISearchController) {
search(searchController.searchBar.text!)
}
func search(_ searchText: String, scope: String="All") {
var predicate:NSPredicate? = nil
let searchBar = searchController.searchBar
if (searchBar.text != nil) {
predicate = NSPredicate(format: "(coinName contains [cd] %@) ", searchBar.text!, searchBar.text!)
}
self.fetchedResultController.fetchRequest.predicate = predicate
do {
try self.fetchedResultController.performFetch()
} catch let error {
print("ERROR: \(error)")
}
tableView.reloadData()
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
if let searchTextField = searchController.searchBar.value(forKey: "_searchField") as? UITextField {
searchTextField.clearButtonMode = .always
}
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
UIView.animate(withDuration: 0.3, animations: { () -> Void in
searchBar.removeFromSuperview()
self.tableView.tableHeaderView = nil
searchBar.showsCancelButton = false
searchBar.resignFirstResponder()
self.fetchedResultController.fetchRequest.predicate = nil
do {
try self.fetchedResultController.performFetch()
print("COUNT FETCHED FIRST: \(self.fetchedResultController.sections?[0].numberOfObjects)")
} catch let error {
print("ERROR: \(error)")
}
self.tableView.reloadData()
}, completion: { finished in
self.navigationController!.navigationBar.alpha = 1
self.navigationController!.isNavigationBarHidden = false
})
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
if let count = fetchedResultController.sections?.first?.numberOfObjects {
print("----> \(count)")
return count
}
return 1
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CoinCell", for: indexPath)
as! CoinCell
if let coin = fetchedResultController.object(at: indexPath) as? Coin {
cell.coinNameLabel.text = coin.coinName
cell.coinValueLabel.text = coin.totalCoinSupply! + "$"
cell.coinImageUrl?.downloadImage(from: coin.imageURL!)
cell.percentageShift.text = "+12.56%"
}
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 120
}
@IBAction func searchFilter( _ sender: UIBarButtonItem) {
tableView.tableHeaderView = searchController.searchBar
searchController.searchBar.becomeFirstResponder()
}
} 扩展CoinViewController:NSFetchedResultsControllerDelegate { func控制器(_ controller:NSFetchedResultsController,didChange anObject:Any,at indexPath:IndexPath?,type:NSFetchedResultsChangeType,newIndexPath:IndexPath?){
switch type {
case .insert:
self.tableView.insertRows(at: [newIndexPath!], with: .automatic)
case .delete:
self.tableView.deleteRows(at: [indexPath!], with: .automatic)
default:
break
}
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
self.tableView.endUpdates()
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
}
答案 0 :(得分:0)
这是在取消搜索时告诉您的功能:
func searchBarCancelButtonClicked(_ searchBar: UISearchBar)
如果过滤了结果,则应重新加载它们并再次调用 reloadData()。
修改强>
我认为这很清楚,但既然你在这里要求完整的代码,那就是:
func searchBarCancelButtonClicked(_ searchBar: UISearchBar)
{
self.fetchedResultController.fetchRequest.predicate = nil
do {
try self.fetchedResultController.performFetch()
tableView.reloadData()
} catch let error {
print("ERROR: \(error)")
}
}
这样您可以在不过滤结果的情况下再次获取结果,然后重新加载表视图。