Custom Searchbar in iOS - ios

Hello i am using UISerchbar in tableview but is there any easy way to create custom searchbar in tableview headerview?
i already check below link but i am not understand.
Custom UISearchBar with UISearchController
How do I use the UISearchBar and UISearchDisplayController
I have added searchDisplayController : :
And This is my code for searchController,
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.searchBar.delegate = self;
self.definesPresentationContext = YES;
[self.searchController.searchBar setBarTintColor:[UIColor darkGrayColor]];
self.tableView.tableHeaderView = self.searchController.searchBar;
I have set delegate for UISearchBarDelegate,UISearchResultsUpdating as well,
and implemented their method ,
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
if (_searchController.isActive && _searchController.searchBar.text.length >0){
NSPredicate *resultPredicate = [NSPredicate
predicateWithFormat:#"SELF.name contains[cd] %#",
searchText];
abcd = [sortedEventArray filteredArrayUsingPredicate:resultPredicate];
NSLog(#"%#",searchResults);
}
}
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController1
{
NSString *searchString = searchController1.searchBar.text;
[self filterContentForSearchText:searchString scope:#"abc"];
//[self filterContentForSearchText:searchString :#"abc"];
[self.tableView reloadData];
}
cancel button event
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
abcd=[sortedEventArray mutableCopy];
[_tableView reloadData];
}
-(void)delete{
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest * allMovies = [[NSFetchRequest alloc] init];
[allMovies setEntity:[NSEntityDescription entityForName:#"Data" inManagedObjectContext:context]];
[allMovies setIncludesPropertyValues:NO]; //only fetch the managedObjectID
NSError * error = nil;
NSArray * movies = [context executeFetchRequest:allMovies error:&error];
//error handling goes here
for (NSManagedObject * movie in movies) {
[context deleteObject:movie];
}
NSError *saveError = nil;
[context save:&saveError];
}
Still Its not working
Thanks in advance :)

There is everythings is complete but there is two little mistakes by me.
1) delete the search bar from Storyboard.
2) Add [self.searchController.searchBar sizeToFit];
in viewDidLoad
Thanks :))

Related

UITable won't refresh even with reload called on main thread

I have a main view controller(SecondViewController) with a UITable and a navigation controller. When a navigation bar button is pressed, a menu drops down from the navigation bar on top of the table. This menu is created by adding a view controller as a subview like so:
//SecondViewController.m
self = sortMenu.secondVC;
[self addChildViewController:sortMenu];
[self.view addSubview:sortMenu.view];
[sortMenu didMoveToParentViewController:self];
sortMenu contains a button that changes the order the cells are displayed in by calling a class method of the main view controller.
//SortMenuViewController.m
- (IBAction)sortButtonPressed:(id)sender {
[_secondVC sortButtonPressed:[sender tag]];
}
In sortButtonPressed, it calls a method to make a fetch request with updated sort filter value.
//SecondViewController.m
-(void)sortButtonPressed:(NSInteger)sortDescriptor{
_sortDescriptor = sortDescriptor;
currentPredicate = [NSPredicate predicateWithFormat:#"dataset & %d > 0", 4];
[self fetchResultsUsingSegmentedControlIndex];
}
The fetch request is performed and returns the data in a new order.
//SecondViewController.m
- (IBAction)fetchResultsUsingSegmentedControlIndex
{
NSString* sectionNameKeyPath = nil;
NSArray* sortDescriptors = nil;
NSSortDescriptor *scientificNameDescriptor = [[NSSortDescriptor alloc] initWithKey:#"scientificName" ascending:YES];
NSSortDescriptor *commonNameFirstDescriptor = [[NSSortDescriptor alloc] initWithKey:#"commonNameFirst" ascending:YES];
NSSortDescriptor *commonNameLastDescriptor = [[NSSortDescriptor alloc]
initWithKey:#"commonNameLast"
ascending:YES
selector:#selector(localizedCaseInsensitiveCompare:)];
if (_sortDescriptor == kSortByCommonNameFirst )
{
sortDescriptors = [[NSArray alloc] initWithObjects:commonNameFirstDescriptor, commonNameLastDescriptor, scientificNameDescriptor, nil];
sectionNameKeyPath = #"commonNameFirst";
}
else if (_sortDescriptor == kSortByCommonNameLast )
{
sortDescriptors = [[NSArray alloc] initWithObjects:commonNameLastDescriptor, commonNameFirstDescriptor, scientificNameDescriptor, nil];
sectionNameKeyPath = #"commonNameLast";
}
else if (_sortDescriptor == kSortByScientificName )
{
sortDescriptors = [[NSArray alloc] initWithObjects:scientificNameDescriptor, commonNameFirstDescriptor, commonNameLastDescriptor, nil];
sectionNameKeyPath = #"scientificName";
}
NSError *error;
NSLog(#"current predicate: %#", currentPredicate);
[[self fetchedResultsControllerWithsectionNameKeyPath:sectionNameKeyPath sortDescriptors:sortDescriptors predicate:currentPredicate] performFetch:&error];
[scientificNameDescriptor release];
[commonNameLastDescriptor release];
[commonNameFirstDescriptor release];
[sortDescriptors release];
NSUInteger sectionsCt = [[speciesFetchedResultsController sections] count];
int sum = 0;
for (int i=1; i < sectionsCt; i++){
id <NSFetchedResultsSectionInfo> sectionInfo = [[speciesFetchedResultsController sections] objectAtIndex:i];
NSUInteger numOfObj = [sectionInfo numberOfObjects];
NSLog(#" in section %d number of objects is %lu ", i, (unsigned long)numOfObj);
sum = sum + numOfObj;
}
[_table performSelectorOnMainThread:#selector(reloadData)
withObject:nil
waitUntilDone:NO];
}
When I call fetchResultsUsingSegmentedControlIndex from the main view controller (before dropping down the sort menu), it works correctly. However, when called from sortMenu, numberOfRowsInSection, numberOfSectionsInTableView, and cellForRowAtIndexPath are not called. I have tried to call reloadData on the main thread with performSelectorOnMainThread and also dispatching it to the main queue, but neither works.
I originally created a sort menu by adding a pickerview to the main view controller on pressing the navigation bar button, and my table reloaded correctly. Since creating a separate view controller for the menu (to have greater design control), it doesn't work.
Ended up using delegation.
// SortMenuViewController.h
#import <UIKit/UIKit.h>
#protocol SortMenuViewControllerDelegate <NSObject>
-(void)sortButtonPressed:(NSInteger)sortDescriptor;
-(void)viewButtonPressed:(NSInteger)viewDescriptor;
#end
#interface SortMenuViewController : UIViewController{
}
//SortMenuViewController.m
- (IBAction)changeSort:(id)sender {
[_delegate sortButtonPressed:[sender tag]];
}
//SecondViewController.h
#interface SecondViewController : UIViewController <NSFetchedResultsControllerDelegate, SortMenuViewControllerDelegate>{
}
-(void)sortButtonPressed:(NSInteger)sortDescriptor{
_sortDescriptor = sortDescriptor;
currentPredicate = [NSPredicate predicateWithFormat:#"dataset & %d > 0", dataset];
[self fetchResultsUsingSegmentedControlIndex];
}

Not able to scroll and select cells displayed in uisearch controller

I have a screen which shows favourite locations and if a user wants to add new location he can search using uisearchcontroller and add it to favourite location's list.
The problem is that once i make the api call for autocomplete the list of searched locations is visible but i cannot select or scroll the table.
I know that the problem is where i set the uisearchcontroller. but i do not know the right way to do it.
I am newbie in iOS so ur suggestions will be welcome.
the following is the GithubRepository for the project(incase ul want to try out the app and make suggestions)
and heres the related code where i beleive the problem exists.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
favList = [[NSMutableArray alloc] init];
searchList = [[NSMutableArray alloc]init];
self.table.dataSource = self;
self.table.delegate = self;
[self initSearch];
}
#pragma mark UI Search methods
-(void) initSearch
{
FavouriteViewController *searchResultsController = [[FavouriteViewController alloc] init];
searchResultsController.table.dataSource = self;
searchResultsController.table.delegate = self;
searchResultsController.table.allowsSelectionDuringEditing = YES;
searchResultsController.table.allowsSelection = YES;
self.search = [[UISearchController alloc] initWithSearchResultsController:searchResultsController];
self.definesPresentationContext = NO;
self.table.tableHeaderView = self.search.searchBar;
self.search.searchResultsUpdater = self;
self.search.searchBar.delegate = self;
self.search.dimsBackgroundDuringPresentation = NO;
}
didSelectRowAtIndex method
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (self.search.active) {
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObjectModel *place = [NSEntityDescription insertNewObjectForEntityForName:#"Place" inManagedObjectContext:context];
NSString *places =[searchList[indexPath.row] valueForKey:#"name"];
if (![favList containsObject:places])
{
NSString *lati = [searchList[indexPath.row] valueForKey:#"lat"];
NSString *longi = [searchList[indexPath.row] valueForKey:#"lon"];
if (places != NULL && lati != NULL && longi != NULL)
{
[place setValue:places forKey:#"placeName"];
[place setValue:lati forKey:#"latitude"];
[place setValue:longi forKey:#"longitude"];
}
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
}
[self.search setActive:NO];
filtered = NO;
[self getalldata];
[self.table reloadData];
}
else
{
NSManagedObject *device = [favList objectAtIndex:indexPath.row];
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.SJI.Weather-App"];
[defaults setObject:[device valueForKey:#"placeName"] forKey:#"favSet"];
[[self navigationController] popToRootViewControllerAnimated:YES];
}
}

Slow UISearchDisplayController with Core Data

I have a TableViewController displaying like 40 000 rows from Core Data with NSFetchedResultsController.
I implemented a live search with a UISearchDisplayController (support for IOS 7).
It's working but typing on the keyboard when searching is very slow...
I'd really appreciate if someone could point me to the right direction and show me where I might be going wrong.
Here is the UISearchResultsUpdating part in my TableViewController
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
ItemSearchScope scopeKey = controller.searchBar.selectedScopeButtonIndex;
[self searchForText:searchString scope:scopeKey];
return YES;
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption
{
NSString *searchString = controller.searchBar.text;
[self searchForText:searchString scope:searchOption];
return YES;
}
- (void)searchForText:(NSString *)searchText scope:(ItemSearchScope)scopeOption
{
if (self.managedObjectContext)
{
NSString *predicateFormat = #"%K CONTAINS[cd] %#";
NSString *searchAttribute1 = #"attribute1";
NSString *searchAttribute2 = #"attribute2";
NSString *searchAttribute3 = #"attribute3";
if (scopeOption == searchScopeDebut) {
predicateFormat = #"%K BEGINSWITH[cd] %#";
}
if (scopeOption == searchScopeFin) {
predicateFormat = #"%K ENDSWITH[cd] %#";
}
NSPredicate *p1 = [NSPredicate predicateWithFormat:predicateFormat, searchAttribute1, searchText];
NSPredicate *p2 = [NSPredicate predicateWithFormat:predicateFormat, searchAttribute2, searchText];
NSPredicate *p3 = [NSPredicate predicateWithFormat:predicateFormat, searchAttribute3, searchText];
NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:#[p1, p2, p3]];
[self.searchFetchRequest setPredicate:predicate];
NSError *error = nil;
self.filteredList = [self.managedObjectContext executeFetchRequest:self.searchFetchRequest error:&error];
if (error)
{
NSLog(#"searchFetchRequest failed: %#",[error localizedDescription]);
}
}
}
I ended up using a NSTimer for delaying the shouldReloadTableForSearchString method. searchTimerPopped selector is triggered only if the user stop typing the keyboard for 2 seconds.
#property (nonatomic, retain) NSTimer *searchTimer;
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
if (self.searchTimer) {
[self.searchTimer invalidate];
self.searchTimer = nil;
}
self.searchTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(searchTimerPopped:) userInfo:searchString repeats:FALSE];
return NO;
}
- (void)searchTimerPopped:(NSTimer *)timer {
NSString *searchString = [timer userInfo];
ItemSearchScope scopeKey = self.searchDisplayController.searchBar.selectedScopeButtonIndex;
[self searchForText:searchString scope:scopeKey];
[self.searchDisplayController.searchResultsTableView reloadData];
}

Why does Core Data fetch request return empty from custom UITableViewCell?

I have a method in ViewController.m called getData which is called inside viewDidLoad:
-(void)getData {
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:#"WorkoutHasExercise" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
request.resultType = NSDictionaryResultType;
request.propertiesToFetch = [NSArray arrayWithObjects:#"exerciseName", #"reps", #"sets", nil];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(workoutName = %#)", _workoutName];
[request setPredicate:pred];
NSManagedObject *matches = nil;
NSError *error;
NSArray *objects = [context executeFetchRequest:request error:&error];
if ([objects count] == 0) {
} else {
[_exercises removeAllObjects];
for (int x = 0; x < [objects count]; x++) {
matches = objects[x];
[_exercises addObject:[matches valueForKey:#"exerciseName"]];
[_totalSets addObject:[matches valueForKey:#"sets"]];
[_totalReps addObject:[matches valueForKey:#"reps"]];
[_currentSets addObject:[NSNumber numberWithInteger:0]];
}
}
[_exercisesTableView reloadData];
}
I also have a custom UITableViewCell with two buttons initiated in cellForRowAtIndexPath:
ActiveWorkoutCell *cell = (ActiveWorkoutCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ActiveWorkoutCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
cell.increaseButton.tag = indexPath.row;
cell.decreaseButton.tag = indexPath.row;
In ActiveWorkoutCell.m I have 2 IBActions for the buttons:
- (IBAction)decreaseSets:(id)sender {
ActiveWorkoutViewController *vc = [[ActiveWorkoutViewController alloc] init];
[vc decreaseSets:[sender tag]];
}
- (IBAction)increaseSets:(id)sender {
ActiveWorkoutViewController *vc = [[ActiveWorkoutViewController alloc] init];
[vc increaseSets:[sender tag]];
}
The IBActions call these 2 methods back in ViewController.m
-(void)increaseSets:(NSInteger)row {
[self getData];
//There will be code here to increase the value of currentSets[row]
}
-(void)decreaseSets:(NSInteger)row {
[self getData]
//Code to decrease value...
}
PROBLEM:
When getData is called from viewDidLoad, it works fine.
The problem occurs when returning to ViewController.m from the IBAction in ActiveWorkoutCell.m.
When I call [self getData] in increaseSets the fetch request returns an empty array. This is what is confusing me - the code works fine when it is first called but not at all when called the second time after the custom cell Action has been triggered.
Here is my viewDidLoad if it helps:
- (void)viewDidLoad {
[super viewDidLoad];
_exercises = [NSMutableArray array];
_totalSets = [NSMutableArray array];
_currentSets = [NSMutableArray array];
_totalReps = [NSMutableArray array];
_titleLabel.text = _workoutName;
_exercisesTableView.allowsSelection = NO;
[self getData];
}
_workoutName is given a value in prepareForSegue in the previous view controller.
I think I found the issue. You are instantiating the "ActivityWorkOutViewController" when the IBAction methods called and it will be a new instance and then in those methods you are calling [self getData] which pointing to the new instance which has no variables instantiated or viewDidLoad happened, so your mutable arrays are not allocated and hence they are empty.
Just use the old instance of the class to get the data.
I am not sure how you are referencing those classes. I am just in a confusion about that. But, you might check the allocations and calling the right class to get the data

make "Next" Button disabled if no cell is checked

THX FOR THE HELP!
I changed the Viewdidload like that and it is working fine for me now! Iam Fetching the location and took a predicate to synchronize the checks and the state of the button
- (void)viewDidLoad
{
[super viewDidLoad];
app = (AppDelegate *) [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [app managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Standort" inManagedObjectContext:context];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ortcheck CONTAINS YES"];
[request setPredicate:predicate];
[request setEntity:entity];
NSError *error = nil;
NSArray *events = [context executeFetchRequest:request error:&error];
int i = events.count;
if (i == 0) {
myWeiter = [[UIBarButtonItem alloc] initWithTitle:#"Weiter" style:UIBarButtonItemStyleBordered target:self action:#selector(nextPressed:)];
self.navigationItem.rightBarButtonItem = myWeiter;
self.navigationItem.rightBarButtonItem.enabled = NO;
}
else {
myWeiter = [[UIBarButtonItem alloc] initWithTitle:#"Weiter" style:UIBarButtonItemStyleBordered target:self action:#selector(nextPressed:)];
self.navigationItem.rightBarButtonItem = myWeiter;
self.navigationItem.rightBarButtonItem.enabled = YES;
}
Add a check counter as an instance member, and initialize it to 0, on each check increase it, and on each uncheck decrease it, after each check set the button:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// snip
//if (cell.checkButton.hidden==YES){
// cell.checkButton.hidden=NO;
//}else {
// cell.checkButton.hidden=YES;
//}
BOOL state = !cell.checkButton.hidden;
cell.checkButton.hidden=state; // simpler
self.counter += (state) ? 1 : -1;
[nextButton setEnabled: counter > 0];
// snap
}

Resources