Using UISearchController to search TableView - ios

I know that Apple deprecated the old Search Display Controller. I have a table with data, and I'm simply making a search bar that will allow the user to search for data (this data only contains alphabetical names) from the table view with a search bar. I was trying to use the following code at one point to detect if the user is typing something:
if(tableView == self.searchDisplayController.searchResultsTableView)
But I cannot because Apple has deprecated the old way. I understand that I have to use the UISearchController now, and I've looked at Apple's documentation and the sample code they provide, but I have not been able to understand it. I've looked everywhere, but have found no solid examples/tutorials on how to do this with objective-c. Can anyone please explain how we use the tableview in conjunction with the UISearchController in order to allow the user to search the data?

I have a simple demo project here
You need a TableviewController to show data,and a TableviewController to show searchResult
For example,(Code from demo project in the link)
Declare a SearchResultViewController
#interface SearchResultViewController : UITableViewController
Then in main tableview
#interface SearchTableViewController()<UISearchBarDelegate,UISearchResultsUpdating>
#property (strong,nonatomic)NSMutableArray * dataArray;
#property (strong,nonatomic)UISearchController * searchcontroller;
#property (strong,nonatomic)SearchResultViewController * resultViewController;
#end
In viewDidLoad,setup everything
self.resultViewController = [[SearchResultViewController alloc] init];
self.searchcontroller = [[UISearchController alloc] initWithSearchResultsController:self.resultViewController];
self.searchcontroller.searchBar.delegate = self;
self.resultViewController.tableView.delegate = self;
[self.searchcontroller.searchBar sizeToFit];
self.searchcontroller.searchResultsUpdater = self;
self.searchcontroller.dimsBackgroundDuringPresentation = NO;
self.definesPresentationContext = YES;
self.tableView.tableHeaderView = self.searchcontroller.searchBar;
Then in delegate method,do real search and update searchResultViewController
#pragma mark - search bar delegate
-(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar{
[searchBar resignFirstResponder];
}
#pragma mark - UISearchResultUpdating
//Do real search,this is up to you
-(void)updateSearchResultsForSearchController:(UISearchController *)searchController{
NSString * searchtext = searchController.searchBar.text;
NSArray * searchResults = [self.dataArray filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
BOOL result = NO;
if ([(NSString *)evaluatedObject hasPrefix:searchtext]) {
result = YES;
}
return result;
}]];
SearchResultViewController *tableController = (SearchResultViewController *)self.searchcontroller.searchResultsController;
tableController.dataArray = searchResults;
[tableController.tableView reloadData];
}

Related

iOS 9 custom transition - animationControllerForDismissedController not called

I am a newbee in iOS development and recently run into this problem with customized transition in iOS 9.
I have an object conforms to UIViewControllerTransitioningDelegate protocol and implements animationControllerForDismissedController, something like:
#implementation MyCustomizedTransitioningDelegate
#pragma mark - UIViewControllerTransitioningDelegate
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
MyCustomizedTransitionAnimator *animator = [[MyCustomizedTransitionAnimator alloc] init];
animator.presenting = NO;
return animator;
}
#end
And the process that triggers the modal transition is something like:
#implementation MyViewController
#pragma mark - Initializers
+ (MyCustomizedTransitioningDelegate *)modalTransitioningDelegateSingletonInstance;
{
static MyCustomizedTransitioningDelegate *delegateInst = nil;
static dispatch_once_t onceToken = 0;
dispatch_once(&onceToken, ^{
delegateInst = [[MyCustomizedTransitioningDelegate alloc] init];
});
return delegateInst;
}
#pragma mark - UIViewController
- (void)dismissViewControllerAnimated:(BOOL)animated completion:(void (^)(void))completion;
{
[self prepareForDismissViewControllerAnimated:animated completion:&completion];
[super dismissViewControllerAnimated:animated completion:completion];
}
- (void)prepareForDismissViewControllerAnimated:(BOOL)animated completion:(dispatch_block_t *)completion;
{
self.presentedViewController.modalPresentationStyle = UIModalPresentationCustom;
self.presentedViewController.transitioningDelegate = [[self class] modalTransitioningDelegateSingletonInstance];
}
#end
Since animationControllerForDismissedController method is not called, the MyCustomizedTransitionAnimator is not created, which leads to its animateTransition not called either, which causes unexpected problem in my app. (Sorry for my poor English...)
I am also attaching the screenshot of stack trace for both iOS8 & iOS9.
In iOS 8, animationControllerForDismissedController is called after the stack trace below.
But in iOS9, transitionDidFinish is called somehow in advance, which I guess probably prevent animationControllerForDismissedController being called?
I was wondering if this is an iOS 9 bug or not. Any explanation or work around solution will be greatly appreciated!
I faced the same issue.
I hope this will help someone.
What fixed it for me is to make the object which applies UIViewControllerTransitioningDelegate protocol as variable instance to keep strong relationship with it.
I think because it gets dismissed after the view is presented first time.
I had the same issue.
Turned out I needed to set the delegate on the navigationController of the UIViewController that contains the trigger button.
Having this old code that didn't work:
UIViewController *dvc = [self sourceViewController];
TransitionDelegate *transitionDelegate = [TransitionDelegate new];
dvc.modalPresentationStyle = UIModalPresentationCustom;
dvc.transitioningDelegate = transitionDelegate;
[dvc dismissViewControllerAnimated:YES completion:nil];
I changed the first line to:
UIViewController *dvc = [self sourceViewController].navigationController;
and it worked.
Hope this helps.
You need to say something like:
MyDestinationViewController *viewController = [[MyDestinationViewController alloc] init];
MyCustomizedTransitioningDelegate *transitioningDelegate = [[MyCustomizedTransitioningDelegate alloc]init];
viewController.transitioningDelegate = transitioningDelegate;
viewController.modalPresentationStyle = UIModalPresentationCustom;
[self presentViewController: viewController animated:YES completion:nil];
Or if you're using segues, in prepareForSegue say something like:
MyDestinationViewController *toVC = segue.destinationViewController;
MyCustomizedTransitioningDelegate *transitioningDelegate = [[MyCustomizedTransitioningDelegate alloc]init];
toVC.transitioningDelegate = transitioningDelegate;

iOS - how can i add events to kal library in Objective C?

I work in project need calendar view with events , i try many libraries but finally i decide to use kal library as its have ability to add events
Calendar.h
#import "Kal.h"
#import "NSDate+Convenience.h"
#import "EventKitDataSource.h"
#interface Calendar : UIViewController<WebService_Delegate , UITableViewDelegate >
{
KalViewController *kal;
id dataSource;
}
Calendar.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Caledar";
kal = [[KalViewController alloc]initWithSelectionMode:KalSelectionModeSingle];
kal.selectedDate = [NSDate dateStartOfDay:[NSDate date]];
kal.delegate = self;
kal.view.frame = CGRectMake(0, 65, kal.view.frame.size.width, kal.view.frame.size.height);
[kal showAndSelectDate:[NSDate date]];
//navController = [[UINavigationController alloc]initWithRootViewController:kal];
// [self.view addSubview:navController.view];
[self initVariable];
[self getEvents];
dataSource = [[EventKitDataSource alloc] init];
kal.dataSource = dataSource;
[self.view addSubview:kal.view];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Display a details screen for the selected event/row.
EKEventViewController *vc = [[EKEventViewController alloc] init];
vc.event = [dataSource eventAtIndexPath:indexPath];
//[vc setEvent:[events_array objectAtIndex:indexPath.row]];
vc.allowsEditing = NO;
[navController pushViewController:vc animated:YES];
}
how can i pass data to dataSource to display it
here how its look like
i need set events list to my events list , i got event duplicated , its read from my calendar
thank you
You need to implement the KalDataSource protocol in an object and set that object as the datasource of your kal object. The protocol can be found here https://github.com/klazuka/Kal/blob/master/src/KalDataSource.h
Add the KalDataSource protocol to your header file
<WebService_Delegate , UITableViewDelegate, KalDataSource>
In the init method of your Calendar object set
kal.datasource = self
Implement the KalDataSource methods in your object

Xcode UISearchBar Code Implementation

I'm currently working on a project where I have to filter through a NSArray (displayed in an UITableView). Problem is, there is neither a XIB file nor a storyboard.
My question is (I already got the predicate and search method et.c set up), how do I get the SearchBar to show up in my program only using code - and ofc I need to be able to work with it.
I'd be really glad about some help with this issue, because every tutorial I found either uses storyboards or xibs :(
Thank you very much up front!
Btw those are the two methods I got so far concerning the search bar, the TableView is also set up already.
-(void) filterContentForSearchText:(NSString *)searchText scope:(NSString *)scope {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains[c] %#", searchText];
self.searchResults = [self.array filteredArrayUsingPredicate:predicate];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self filterContentForSearchText:searchString scope:[[self.searchDisplayController.searchBar scopeButtonTitles]objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
return YES;
}
You can do something like this:
In your .h add this:
#property (nonatomic,strong) UISearchBar *searchBar;
Add this in your viewDidLoad method
self.searchBar = [[UISearchBar alloc]init];
self.searchBar.frame = CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.height);
self.searchBar.delegate = self;
//Customize the searchBar
[self.view addSubview:self.searchBar];
And whenever you want to search, press the search button within the keyboard. A delegate will be called when you do this. Like so,
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{
[searchBar resignFirstResponder];
//Do some search
}
You can access the entered the text using the searchBar.text property. I am assuming that you have implemented the relevant protocols.
If there is no XIB file and no Storyboard, it is initiated somewhere in the code (probably in the viewDidload) looking something like this.
UISearchBar *searchBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0, 0, 100, 20)];
searchBar.delegate = self;
//etc..
Now first add a property in the interface
#property (nonatomic, strong)UISearchBar *searchBar;
And change this line in the viewDidLoad:
self.searchBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0, 0, 100, 20)];
Now you can us self.searchBar anywhere in your code.
Edit:
And don't forget to add this to the interface if it wasn't already:
#interface ViewController () <UISearchBarDelegate, UISearchDisplayDelegate>

Passing Data from Slide menu to UITableViewController through UINavigationViewController

How can I pass data from UINavigationController to The root UITableViewController?
I have implemented the ECSlidingViewController (https://github.com/edgecase/ECSlidingViewController). User selects one of the cells in the menu that correspond to different urls I want to display information from on my tableView that sitts on top of the UINavigationController. (u know the default combination that u get my dragging UINavigationController to ur storyboard). I am able to get the data from the sliding menu to my navigationController now I am trying to pass that same info on my tableview?
In my menu I have:
UINavigationController *newTopViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"NavigationTop"];
newTopViewController = [(NavigationTopViewController*)newTopViewController initWithCinema:self.myCinema];
In UINaviationController:
- (id)initWithCinema:(Cinema *)cinema {
self = [super init];
if(self) {
_myCinema = [[Cinema alloc] init];
_myCinema = cinema;
}
return self;
}
- (void) viewDidLoad {
[super viewDidLoad];
// this log works I get the info to here.
NSLog(#"url(navigation):%#", self.myCinema.cinemaURL);
//MoviesTableViewController *moviesTableViewController = [[MoviesTableViewController alloc] initWithCinema:self.myCinema];
//UITableViewController *newTopViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"MoviesTable"];
//NavigationTopViewController *newTopViewController = [[NavigationTopViewController alloc] initWithCinema:self.myCinema];
//newTopViewController = [(MoviesTableViewController *)newTopViewController initWithCinema:self.myCinema];
//[self performSegueWithIdentifier:nil sender:self.myCinema];
[self prepareForSegue:nil sender:self.myCinema.cinemaURL];
}
In my UITableView:
- (void)setCinema:(Cinema *)cinema {
// works here too
NSLog(#"Table(setCinema):%#", cinema.cinemaURL);
self.myCinema = [[Cinema alloc] init];
if(!cinema) {
cinema.cityIndex = kAstanaIndex;
cinema.name = kKeruen;
cinema.nameForText = kKeruenText;
cinema.cinemaURL = kKeruenURL;
cinema.cinemaURLTomorrow = kKeruenURLtomorrow;
}
self.myCinema = cinema;
// works here too!!!
NSLog(#"Table(myCinema):%#", self.myCinema.cinemaURL);
}
However its gone in viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
// set delegate to self
self.tableView.delegate = self;
// set loading theater's url
// does not work here: I GET NULL !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
NSLog(#"url(moviesTable):%#", self.myCinema.cinemaURL);
_model = [[MovieModel alloc] initWithURL:self.myCinema.cinemaURL];
}
None of the methods I have tried (commented in Navigation worked...) at least for me. Please give me any suggestions. Thank you in advance.
UINavigationController does not hold any data, but rather a stack of view controllers. I'd recommend you check out frameworks such as the free Sensible TableView. The framework will automatically handle detail view generation and passing data between them. Saves me tons of development time in my projects.

object becomes null when passed to another view controller

In the iOS application, I need to pass an object from one view controller to another and then switch to the new view controller. The goal is to simply relay the information. However, the object becomes NULL and is devoid of any information when the next view showed up. what? could be the reason?
Below is part of my code.
#pragma mark - Table view delegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
BIDCourse *course = self.courses[indexPath.row];
NSString *sub = course.subject;
BIDSubjectMainTwoViewController *subjectController=[[BIDSubjectMainTwoViewController alloc] init];
subjectController.title = sub;
subjectController.course=course;
[self.navigationController pushViewController:subjectController animated:YES];
}
BIDCourse *course is my custom subclass to NSObject, which has some NSStrings, and it's not nil, but when I pass it onto the next view controller, it becomes NULL.
I have met a problem like you , when I pass a object to another viewController , it has been released.
I think this is a defect of ARC , ARC think your subjectController may be no use , so it release the subjectController. Make your subjectController as a property , so ARC will not release when you pass it to another viewController.
such as :
#pragma mark - Table view delegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
BIDCourse *course = self.courses[indexPath.row];
NSString *sub = course.subject;
_subjectController=[[BIDSubjectMainTwoViewController alloc] init];
_subjectController.title = sub;
_subjectController.course=course;
[self.navigationController pushViewController:_subjectController animated:YES];
}
Could the problem lie in BIDSubjectMainTwoViewController.m?
subjectController.title = sub;
subjectController.course = course;
in your BIDSubjectMainTwoViewController.m file, did you #synthesize your properties?
#synthesize title = _title;
#synthesize course = _course;
You could also pass the variables along with an init function ala:
BIDSubjectMainTwoViewController.h
- (id)initWithTitle:(NSString *)title
andCourse:(BIDCourse *)course;
BIDSubjectMainTwoViewController.m
- (id)initWithTitle:(NSString *)title
andCourse:(BIDCourse *)course
{
self = [super init];
if (self) {
// Custom initialization
_title=title;
_course = course;
}
return self;
}
I encountered this similar behavior. My solution was to make a copy of the object. For your case:
BIDCourse *course = [self.courses[indexPath.row] copy];
And make sure you implement copyWithZone in the BIDCourse .m fike.
-(id)copyWithZone:(NSZone*) zone
Try this:
BIDSubjectMainTwoViewController.h
NSString *strTemp;
#property(nonatomic,retain) NSString *strTemp;
-(void) setValuestrTemp : (NSString *) str;
.m file
#synthesize strTemp;
// Write setter method
-(void) setValuestrTemp : (NSString *) str {
self.strTemp = str;
}
and use strTemp in viewWillAppear.
//Now use it
BIDSubjectMainTwoViewController *subjectController=[[BIDSubjectMainTwoViewController alloc] init];
[subjectController setValuestrTemp:sub];
[self.navigationController pushViewController:_subjectController animated:YES];
Use
NSString *sub = [course.subject copy];
subjectController.course=[course copy];
implement delegate in BIDCourse
-(id)copyWithZone:(NSZone*) zone

Resources