The search and everything else works fine except when I click Cancel on the search bar, an empty screen appears with the empty search bar on it and the navigation bar of the original table view. The original, unfiltered, array from Core Data is not reloaded. I have checked the "Shows cancel button" in the storyboard. I have researched many posts and articles, but no suggestions have worked. The console messages show that after the Cancel button is pressed, among other messages I see the "Events after Fetch:" is executed twice. The second (last) time it has all my managed objects/events in it, but then "filtered array:" is blank, "events:" is blank, "events.self.count:" = 0, searchBarText is blank, self.events.count = 0.
EventViewController.h file:
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@interface EventViewController: UITableViewController <UISearchResultsUpdating, UISearchControllerDelegate, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate>
{
IBOutlet UISearchBar *searchBar;
}
@end
EventViewController.m file:
#import "EventViewController.h"
#import <CoreData/CoreData.h>
#import "EventDetailViewController.h"
@interface EventViewController ()
@property (nonatomic, strong) NSMutableArray *events;
@property (nonatomic, strong) UISearchController *searchController;
@property(nonatomic, weak) id< UISearchResultsUpdating > searchResultsUpdater;
@property (nonatomic,strong) UISearchBar *_searchBar;
@property(nonatomic, assign) BOOL obscuresBackgroundDuringPresentation;
@property(nonatomic, weak) id< UISearchControllerDelegate > delegate;
//@property(nonatomic, assign, getter=isActive) BOOL active;
@end
@implementation EventViewController
NSMutableArray *events;
- (NSManagedObjectContext *)managedObjectContext {
NSLog(@"Setting up managed object context");
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:@selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
// Fetch the events from persistent data store
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Event"];
self.events = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"name contains[c] %@", self.searchController.searchBar.text];
self.events = [[self.events filteredArrayUsingPredicate:resultPredicate] mutableCopy];
}
- (BOOL)shouldReloadTableForSearchString:(UISearchController *)searchController
{
return YES;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.dimsBackgroundDuringPresentation = false;
self.tableView.tableHeaderView = self.searchController.searchBar;
self.definesPresentationContext = true;
self.searchController.searchBar.delegate = self;
self.searchController.delegate = self;
self.searchController.obscuresBackgroundDuringPresentation = NO;
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
[self.searchController.searchBar becomeFirstResponder];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Fetch the events from persistent data store
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Event"];
self.events = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[self.tableView reloadData];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
self.searchController.searchBar.text = nil;
[self.searchController.searchBar resignFirstResponder];
[self.tableView reloadData];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
{
return [self.events count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
NSManagedObject *event = [self.events objectAtIndex:indexPath.row];
[cell.textLabel setText:[NSString stringWithFormat:@"%@", [event valueForKey:@"name"]]];
{
event = [events objectAtIndex:indexPath.row];
NSManagedObject *event = [self.events objectAtIndex:indexPath.row];
[cell.textLabel setText:[NSString stringWithFormat:@"%@", [event valueForKey:@"name"]]];
}
return cell;
}
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the specified item to be editable.
return YES;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSManagedObjectContext *context = [self managedObjectContext];
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete object from database
[context deleteObject:[self.events objectAtIndex:indexPath.row]];
NSError *error = nil;
if (![context save:&error]) {
NSLog(@"Can't Delete! %@ %@", error, [error localizedDescription]);
return;
}
// Remove event from table view
[self.events removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
#pragma mark - Navigation
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)send
{
if ([[segue identifier] isEqualToString:@"UpdateEvent"]) {
NSManagedObject *selectedEvent = [self.events objectAtIndex:[[self.tableView indexPathForSelectedRow] row]];
EventDetailViewController *destViewController = segue.destinationViewController;
destViewController.event = selectedEvent;
}
}
@end
If you are calling the cancel function you should not filter the array, so you should not execute the lines i mentioned below at that time, for this you may check the length of self.searchController.searchBar.text
or you can set a boolean to check if cancel is clicked or text is entered in the textfield
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"name contains[c] %@", self.searchController.searchBar.text];
self.events = [[self.events filteredArrayUsingPredicate:resultPredicate] mutableCopy];