In my app, I'm working with UISearchBar where user will search from an NSMutableArray by searching with user name. Here is my method for searching user from NSMutableArray
- (void)searchTableList
{
NSString *searchString = searchBar.text;
NSMutableArray *searchArray = [[NSMutableArray alloc] init];
for (NSDictionary *dictionary in contentList)
{
NSArray *array = [dictionary objectForKey:#"username"];
[searchArray addObject:array];
}
for (NSString *sTemp in searchArray)
{
NSRange titleResultsRange = [sTemp rangeOfString:searchString options:NSCaseInsensitiveSearch];
if (titleResultsRange.length > 0)
[filteredContentList addObject:sTemp];
}
}
And Here is how I'm configuring UITableView for showing search results
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"SearchListTableViewCell";
NSMutableDictionary *dict=[contentList objectAtIndex:indexPath.row];
SearchListTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"SearchListTableViewCell" owner:nil options:nil];
cell = (SearchListTableViewCell*)[topLevelObjects objectAtIndex:0];
cell.backgroundColor=[UIColor colorWithRed:239.0/255 green:239.0/255 blue:239.0/255 alpha:1];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}
// Configure the cell...
if (isSearching)
{
cell.friendName.text = [filteredContentList objectAtIndex:indexPath.row];
NSMutableArray *searchImageArray=[[NSMutableArray alloc]init];
for (NSDictionary *dictionary in contentList)
{
NSArray *imageArray=[dictionary objectForKey:#"thumbnail_path_150_150"];
NSLog(#"image arrayt is %#",imageArray);
[searchImageArray addObject:imageArray];
}
for (NSString *imageS in searchImageArray) {
NSRange title=[imageS rangeOfString:cell.friendName.text options:NSCaseInsensitiveSearch];
if (title.length>0) {
[filteredImage addObject:imageS];
}
}
NSString *url=[NSString stringWithFormat:#"%#/get_image?avatar=%#",BaseURL,[filteredImage objectAtIndex:indexPath.row]];
url=[url stringByReplacingOccurrencesOfString:#"\\" withString:#"/"];
UIImage* myImage = [UIImage imageWithData:
[NSData dataWithContentsOfURL:
[NSURL URLWithString:url]]];
[cell.friendProfileImage setImage:myImage];
NSLog(#"filtered Image data %lu",(unsigned long)filteredImage.count);
NSLog(#"filtered content list data %lu",(unsigned long)filteredContentList.count);
}
else
{
cell.friendName.text =[dict objectForKey:#"username"];
NSString *url=[NSString stringWithFormat:#"%#/get_image?avatar=%#",BaseURL,[dict objectForKey:#"thumbnail_path_150_150"]];
url=[url stringByReplacingOccurrencesOfString:#"\\" withString:#"/"];
UIImage* myImage = [UIImage imageWithData:
[NSData dataWithContentsOfURL:
[NSURL URLWithString:url]]];
[cell.friendProfileImage setImage:myImage];
}
return cell;
}
Now I want to fetch the rest data of searched user name from NSMutableDictionary. Here is my dictionary.
(
{
jid = "hey#196.0.0.1";
"thumbnail_path_150_150" = "E\\path\\to\\getImage\\files\\heythumbnail";
username = hey;
},
{
jid = "tweety#196.0.0.1";
"thumbnail_path_150_150" = "E:\\path\\to\\getImage\\files\\tweetythumbnail";
username = tweety;
}
)
Here I want to get the image of searched user. If user searches hey, It must show "thumbnail_path_150_150"
="E\\path\\to\\getImage\\files\\heythumbnail"; this image on tableViewCell. I tried my code for setting image But it replaces image when two users have same name. Like if one user is Ray and another is Blueray , then it changes the image of both. I know i wrote too much. But I'm really confused at this point. Please anyone help solving this issue.
Apply a NSPredicate to filter your array and then use this array to populate the tableView
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"username contains[c] %#",_search_bar.text];
NSArray *filteredArray = [yourMainArray filteredArrayUsingPredicate:predicate];
NSLog(#"here is the filteredCandyArray%#",filteredCandyArray);
//set it to the array you use to fill the table
_dataSourceArray = _filteredCandyArray;
//go!
[_yourTable reloadData];
String comparisons are by default case and diacritic sensitive. You can modify an operator using the key characters c and d within square braces to specify case and diacritic insensitivity respectively, for example firstName BEGINSWITH[cd] $FIRST_NAME.
BEGINSWITH: The left-hand expression begins with the right-hand expression.
CONTAINS: The left-hand expression contains the right-hand expression.
ENDSWITH: The left-hand expression ends with the right-hand expression.
LIKE: The left hand expression equals the right-hand expression: ? and * are allowed as wildcard characters, where ? matches 1 character and * matches 0 or more characters.
MATCHES: The left hand expression equals the right hand expression .
or further details please visit http://nshipster.com/nspredicate/
Simplest way to do this is by using predicates and with a little modifications your code can go somewhat like this
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"username == %#", #"ray"];
NSArray *searchedArray = [rootArray filteredArrayUsingPredicate:predicate];
The above code will only return values where username is ray and not Ray or RAY etc
I recommend you to use Search Bar and Search Display Controller rather than Search Bar.
Also have a look at the following code, it covers everything you want.
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#pragma mark
#pragma mark - View Lifecycle
-(void)viewDidLoad
{
[super viewDidLoad];
NSDictionary *dic1 = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:#"1", #"India", #"IN", #"+91", nil] forKeys:[NSArray arrayWithObjects:#"CountryId", #"CountryName", #"CountryCode", #"ISDCode", nil]];
NSDictionary *dic2 = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:#"2", #"Australia", #"AU", #"+61", nil] forKeys:[NSArray arrayWithObjects:#"CountryId", #"CountryName", #"CountryCode", #"ISDCode", nil]];
NSDictionary *dic3 = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:#"3", #"New Zealand", #"NZ", #"+64", nil] forKeys:[NSArray arrayWithObjects:#"CountryId", #"CountryName", #"CountryCode", #"ISDCode", nil]];
NSDictionary *dic4 = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:#"4", #"South Africa", #"SA", #"+27", nil] forKeys:[NSArray arrayWithObjects:#"CountryId", #"CountryName", #"CountryCode", #"ISDCode", nil]];
NSDictionary *dic5 = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:#"5", #"England", #"EN", #"+44", nil] forKeys:[NSArray arrayWithObjects:#"CountryId", #"CountryName", #"CountryCode", #"ISDCode", nil]];
NSDictionary *dic6 = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:#"6", #"Israel", #"IS", #"+972", nil] forKeys:[NSArray arrayWithObjects:#"CountryId", #"CountryName", #"CountryCode", #"ISDCode", nil]];
NSDictionary *dic7 = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:#"7", #"Afghanistan", #"AF", #"+93", nil] forKeys:[NSArray arrayWithObjects:#"CountryId", #"CountryName", #"CountryCode", #"ISDCode", nil]];
NSDictionary *dic8 = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:#"8", #"Ireland", #"IR", #"+353", nil] forKeys:[NSArray arrayWithObjects:#"CountryId", #"CountryName", #"CountryCode", #"ISDCode", nil]];
NSDictionary *dic9 = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:#"9", #"China", #"CN", #"+86", nil] forKeys:[NSArray arrayWithObjects:#"CountryId", #"CountryName", #"CountryCode", #"ISDCode", nil]];
arrTotalCountries = [NSArray arrayWithObjects:dic1, dic2, dic3, dic4, dic5, dic6, dic7, dic8, dic9, nil];
}
#pragma mark
#pragma mark - UITableView delegate, datasource methods
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(tableView == self.searchDisplayController.searchResultsTableView){
return [arrFilteredCountries count];
}
else{
return [arrTotalCountries count];
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [NSString stringWithFormat:#"CellIdentifier%ld%ld",(long)indexPath.section,(long)indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSDictionary *dicCountry;
if (tableView == self.searchDisplayController.searchResultsTableView) {
dicCountry = [arrFilteredCountries objectAtIndex:indexPath.row];
} else {
dicCountry = [arrTotalCountries objectAtIndex:indexPath.row];
}
NSString *strShow = [NSString stringWithFormat:#"%# (%#)",[dicCountry objectForKey:#"CountryName"],[dicCountry objectForKey:#"ISDCode"]];
cell.textLabel.text = strShow;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSDictionary *dicCountry;
if (tableView == self.searchDisplayController.searchResultsTableView) {
dicCountry = [arrFilteredCountries objectAtIndex:indexPath.row];
} else {
dicCountry = [arrTotalCountries objectAtIndex:indexPath.row];
}
NSString *countryName = [dicCountry objectForKey:#"CountryName"];
NSString *CountryISDCode = [dicCountry objectForKey:#"ISDCode"];
[self showAlertWithTitle:countryName message:CountryISDCode];
}
#pragma mark
#pragma mark - Other method Implementation
-(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(SELF.CountryName BEGINSWITH[cd] %#) OR (SELF.ISDCode CONTAINS[cd] %#)", searchText, searchText];
arrFilteredCountries = [arrTotalCountries filteredArrayUsingPredicate:predicate];
}
-(void)showAlertWithTitle:(NSString *)title message:(NSString *)message
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
#pragma mark
#pragma mark - UISearchbar controller delegate
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
#pragma mark
#pragma mark - Memory management
-(void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
Also add a comment in case, anyone stuck at some point. I have implemented this and it works nicely. It's a short and best way to add search function to your Table view.
Related
I am parsing a json to display the contents in the tableview. I have the array containing parsed json being populated in getReceivedData which is called after the UITAbleView Delegate methods. So it is problem in populating tableview as when the compiler attempts to populate it the array is not yet initialized.
- (void)getReceivedData:(NSMutableData *)data sender:(RestAPI *)sender{
NSError * error=nil;
NSArray *receivedData = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
NSString *dictionaryKey=#"department";
NSString *predicateString=#"software";
NSPredicate *predicate=[NSPredicate predicateWithFormat:#" %K == %# ", dictionaryKey,predicateString];
NSArray *shortlisted=[receivedData filteredArrayUsingPredicate:predicate];
for(int i = 0; i<shortlisted.count; i++)
{
NSDictionary *detailItems=[shortlisted objectAtIndex:i];
NSString *name=[detailItems objectForKey:#"emp_name"];
NSString *designation=[detailItems objectForKey:#"designation"];
NSString *email=[detailItems objectForKey:#"email"];
NSString *phone_no=[detailItems objectForKey:#"phone_no"];
// NSString *image=[detailItems objectForKey:#"url_path"];
dictionary1=[NSMutableDictionary dictionaryWithObjectsAndKeys:
name, #"keyname",
designation, #"keydesignation",
email, #"keyid",
phone_no, #"keyphone",
nil];
[myObject1 addObject:dictionary1];
}
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:
(NSInteger)section{
if(isfiltered==YES){
return [filteredArray count];
}
else{
return [myObject1 count];
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
MyTableCell *cell=[tableView dequeueReusableCellWithIdentifier:#"myCell"];
if(!cell){
[tableView registerNib:[UINib nibWithNibName:#"MyTableCell" bundle:nil]
forCellReuseIdentifier:#"myCell"];
cell=[tableView dequeueReusableCellWithIdentifier:#"myCell"];
}
if(isfiltered==NO)
{
NSDictionary * tmpdict= [myObject objectAtIndex:indexPath.row];
cell.nameLabel.text=[NSMutableString stringWithFormat:#"%#",[tmpdict objectForKeyedSubscript:#"keyname"]];
cell.designationLabel.text=[NSMutableString stringWithFormat:#"%#",[tmpdict objectForKeyedSubscript:#"keydesignation"]];
cell.idLabel.text=[NSMutableString stringWithFormat:#"%#",[tmpdict objectForKeyedSubscript:#"keyid"]];
cell.phoneLabel.text=[NSMutableString stringWithFormat:#"%#",[tmpdict objectForKeyedSubscript:#"keyphone"]];
cell.mainImg.image = [UIImage imageNamed:[tmpdict objectForKeyedSubscript:#"keyimage"]];
}
else{
NSDictionary * tmpdict= [filteredArray objectAtIndex:indexPath.row];
cell.nameLabel.text=[NSMutableString stringWithFormat:#"%#",[tmpdict objectForKeyedSubscript:#"keyname"]];
cell.designationLabel.text=[NSMutableString stringWithFormat:#"%#",[tmpdict objectForKeyedSubscript:#"keydesignation"]];
cell.idLabel.text=[NSMutableString stringWithFormat:#"%#",[tmpdict objectForKeyedSubscript:#"keyid"]];
cell.phoneLabel.text=[NSMutableString stringWithFormat:#"%#",[tmpdict objectForKeyedSubscript:#"keyphone"]];
cell.mainImg.image = [UIImage imageNamed:[tmpdict objectForKeyedSubscript:#"keyimage"]];
}
return cell;
}
This window was supposed to view the table
In a mutable dictionary first you have to give object then its key. You are doing wrong
for(int i = 0; i<shortlisted.count; i++)
{
NSDictionary *detailItems=[shortlisted objectAtIndex:i];
NSString *name=[detailItems objectForKey:#"emp_name"];
NSString *designation=[detailItems objectForKey:#"designation"];
NSString *email=[detailItems objectForKey:#"email"];
NSString *phone_no=[detailItems objectForKey:#"phone_no"];
dictionary1=[NSMutableDictionary dictionaryWithObjectsAndKeys:
name,#"keyname",
designation,#"keydesignation",
email,#"keyid",
phone_no,#"keyphone",
nil];
[myObject1 addObject:dictionary1];
}
Actually this is not correct way to intialize dictionary as you did, #"%#" is used %# is a placeholder in a format string for any object.
dictionary1=[NSMutableDictionary dictionaryWithObjectsAndKeys:
name,#"keyname",
designation,#"keydesignation",
email,#"keyid",
phone_no,#"keyphone",
nil];
I have added search bar for collection view using programatically .But when i enter the names to search nothing shows.I have some section also and each section contains some data.
Here is my code:
#interface ViewController ()
{
NSMutableArray *arrayPDFName;
NSMutableArray *titleArray;
}
#property (nonatomic,strong) NSArray *dataSourceForSearchResult;
#property (nonatomic) BOOL searchBarActive;
#property (nonatomic) float searchBarBoundsY;
#property (nonatomic,strong) UISearchBar *searchBar;
#property (nonatomic,strong) UIRefreshControl *refreshControl;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.dataSourceForSearchResult = [NSArray new];
titleArray = [NSMutableArray array];
[self getdata];
self.mycollectionView.dataSource = self;
self.mycollectionView.delegate = self;
[self.mycollectionView reloadData];
}
-(NSString*)sha256HashFor:(NSString*)input
{
const char* str = [input UTF8String];
unsigned char result[CC_SHA256_DIGEST_LENGTH];
CC_SHA256(str, strlen(str), result);
NSMutableString *ret = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH*2];
for(int i = 0; i<CC_SHA256_DIGEST_LENGTH; i++)
{
[ret appendFormat:#"%02x",result[i]];
}
return ret;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self prepareUI];
}
-(void)getdata {
NSString *userName = #“username#yahoo.com";
NSString *password = #“password”;
NSData *plainData = [password dataUsingEncoding:NSUTF8StringEncoding];
NSString *base64String = [plainData base64EncodedStringWithOptions:0];
base64String=[self sha256HashFor: base64String];
NSString *urlString = #"https://api.exampleport/user/orderid/files";
NSMutableURLRequest *request= [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:#"GET"];
// basic authendication
NSString *authStr = [NSString stringWithFormat:#"%#:%#", userName, base64String];
NSData *authData = [authStr dataUsingEncoding:NSUTF8StringEncoding];
//header-field
NSString *authValue = [NSString stringWithFormat:#"Basic %#", [authData base64Encoding]];
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *str = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
NSError * error;
self->arrayPDFName = [[NSMutableArray alloc]init];
NSDictionary *jsonResults = [NSJSONSerialization JSONObjectWithData:returnData options:NSJSONReadingMutableContainers error:nil];
NSDictionary *dictOriginal = jsonResults[#“dark”];
[titleArray addObject:[NSString stringWithFormat:#"dark(%#)”, dictOriginal[#"count"]]];
NSDictionary *dictOriginal2 = jsonResults[#"orange”];
[titleArray addObject:[NSString stringWithFormat:#"orange(%#)”, dictOriginal2[#"count"]]];
NSDictionary *dictOriginal3 = jsonResults[#"pencill”];
[titleArray addObject:[NSString stringWithFormat:#"pencill(%#)”, dictOriginal3[#"count"]]];
NSDictionary *dictOriginal4 = jsonResults[#"smart”];
[titleArray addObject:[NSString stringWithFormat:#"smart(%#)”, dictOriginal4[#"count"]]];
NSArray *arrayFiles = [NSArray arrayWithObjects: dictOriginal, dictOriginal2, dictOriginal3, dictOriginal4, nil];
NSLog(#"str: %#", titleArray);
for (NSDictionary *dict in arrayFiles) {
NSMutableArray *arr = [NSMutableArray array];
NSArray *a = dict[#"files"];
for(int i=0; i < a.count; i ++) {
NSString *strName = [NSString stringWithFormat:#"%#",[[dict[#"files"] objectAtIndex:i] valueForKey:#"name"]];
// NSLog(#"str: %#", strName);
[arr addObject:strName];
}
[arrayPDFName addObject:arr];
}
//Get plist path
NSString *errorDesc;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory1 = [paths objectAtIndex:0];
NSString *plistPath = [documentsDirectory1 stringByAppendingPathComponent:#"SampleData.plist"];
//NSLog(#"plistPath : %#",plistPath);
//Save data from json to plist
NSString *error1;
returnData = [NSPropertyListSerialization dataFromPropertyList:jsonResults
format:NSPropertyListXMLFormat_v1_0
errorDescription:&error];
if(returnData ) {
if ([returnData writeToFile:plistPath atomically:YES]) {
NSLog(#"Data successfully saved.");
}else {
NSLog(#"Did not managed to save NSData.");
}
}
else {
NSLog(#"%#",errorDesc);
}
// NSArray *stringsArray = [NSArray arrayWithContentsOfFile:plistPath];
NSDictionary *stringsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistPath];
// NSLog(#"str: %#", stringsDictionary);
}
//delegate method for header
-(UICollectionReusableView*) collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
HeaderView * header = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"myHeader" forIndexPath:indexPath];
header.myHeaderLabel.text = titleArray[indexPath.section];
return header;
}
#pragma mark - UICollectionView Datasource
-(NSInteger) numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return titleArray.count;
}
-(NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
if (self.searchBarActive) {
return self.dataSourceForSearchResult.count;
}
NSArray *a = arrayPDFName[section];
if (a.count == 0)
{
return 1;
}
else
{
return a.count;
}
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
return CGSizeMake(0, 80);
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath: (NSIndexPath *)indexPath {
VenueCell *cell = [cv dequeueReusableCellWithReuseIdentifier:#"mycell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor whiteColor];
cell.imgV.image = [UIImage imageNamed:#"doc1.png"];
if (self.searchBarActive) {
cell.myLabel.text = _dataSourceForSearchResult[indexPath.section][indexPath.row];
}else{
NSArray *a = arrayPDFName[indexPath.section];
if (a.count == 0) {
cell.myLabel.text = #"NO DATA";
return cell;
}
cell.myLabel.text = a[indexPath.row];
}
return cell;
}
//////////////////////////for search bar //////////
#pragma mark - actions
-(void)refreashControlAction{
[self cancelSearching];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// stop refreshing after 2 seconds
[self.mycollectionView reloadData];
[self.refreshControl endRefreshing];
});
}
#pragma mark - search
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope{
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"self contains[c] %#", searchText];
self.dataSourceForSearchResult = [self->arrayPDFName filteredArrayUsingPredicate:resultPredicate];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
// user did type something, check our datasource for text that looks the same
if (searchText.length>0) {
// search and reload data source
self.searchBarActive = YES;
[self filterContentForSearchText:searchText
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
[self.mycollectionView reloadData];
}else{
// if text lenght == 0
// we will consider the searchbar is not active
self.searchBarActive = NO;
}
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar{
[self cancelSearching];
[self.mycollectionView reloadData];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{
self.searchBarActive = YES;
[self.view endEditing:YES];
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar{
// we used here to set self.searchBarActive = YES
// but we'll not do that any more... it made problems
// it's better to set self.searchBarActive = YES when user typed something
[self.searchBar setShowsCancelButton:YES animated:YES];
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar{
// this method is being called when search btn in the keyboard tapped
// we set searchBarActive = NO
// but no need to reloadCollectionView
self.searchBarActive = NO;
[self.searchBar setShowsCancelButton:NO animated:YES];
}
-(void)cancelSearching{
self.searchBarActive = NO;
[self.searchBar resignFirstResponder];
self.searchBar.text = #"";
}
#pragma mark - prepareVC
-(void)prepareUI{
[self addSearchBar];
[self addRefreshControl];
}
-(void)addSearchBar{
if (!self.searchBar) {
self.searchBarBoundsY = self.navigationController.navigationBar.frame.size.height + [UIApplication sharedApplication].statusBarFrame.size.height;
self.searchBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0,self.searchBarBoundsY, [UIScreen mainScreen].bounds.size.width, 50)];
self.searchBar.searchBarStyle = UISearchBarStyleMinimal;
self.searchBar.tintColor = [UIColor whiteColor];
self.searchBar.barTintColor = [UIColor whiteColor];
self.searchBar.delegate = self;
self.searchBar.placeholder = #"Search here";
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setTextColor:[UIColor whiteColor]];
// add KVO observer.. so we will be informed when user scroll colllectionView
[self addObservers];
}
if (![self.searchBar isDescendantOfView:self.view]) {
[self.view addSubview:self.searchBar];
}
}
-(void)addRefreshControl{
if (!self.refreshControl) {
self.refreshControl = [UIRefreshControl new];
self.refreshControl.tintColor = [UIColor whiteColor];
[self.refreshControl addTarget:self
action:#selector(refreashControlAction)
forControlEvents:UIControlEventValueChanged];
}
if (![self.refreshControl isDescendantOfView:self.mycollectionView]) {
[self.mycollectionView addSubview:self.refreshControl];
}
}
-(void)startRefreshControl{
if (!self.refreshControl.refreshing) {
[self.refreshControl beginRefreshing];
}
}
Where i am doing mistake and what i need to change to work.Thanks in advance!
It seems your arrayPDFName have array object and each array object have string object. There are two ways to filter you array.
Way - 1
If you want to get the list of array which has the search string the use SUBQUERY with your predicate. Like below.
NSArray *a1 = #[#"a1", #"a2", #"a3"];
NSArray *a2 = #[#"a1", #"a2", #"a3"];
NSArray *a3 = #[#"a1", #"a2", #"a3"];
NSArray *a4 = #[#"a2", #"a3"];
NSArray *allA = #[a1, a2, a3, a4];
NSPredicate *pre = [NSPredicate predicateWithFormat:#"SUBQUERY(SELF, $a, $a == %#).#count > 0", #"a1"];
NSArray *a = [allA filteredArrayUsingPredicate:pre];
Way - 2
If you want to get the search string alone from each array object then follow the below,
NSMutableArray *fa = [[NSMutableArray alloc] init];
for (NSArray *a in allA) {
NSPredicate *p = [NSPredicate predicateWithFormat:#"self CONTAINS[c] %#", #"a3"];
[fa addObjectsFromArray:[a filteredArrayUsingPredicate:p]];
}
Note: Above code done with same sample data. Replace it as you want.
As per your code replace the below code
-(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
NSMutableArray *fa = [[NSMutableArray alloc] init];
for (NSArray *a in arrayPDFName) {
NSPredicate *p = [NSPredicate predicateWithFormat:#"self CONTAINS[c] %#", searchText];
[fa addObjectsFromArray:[a filteredArrayUsingPredicate:p]];
}
self.dataSourceForSearchResult = [NSArray arrayWithArray:fa];
}
-(NSInteger) numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
if(self.searchBarActive)
return 1;
return titleArray.count;
}
In cellForItemAtIndexPath
cell.myLabel.text = _dataSourceForSearchResult[indexPath.row];
I have created a app that fetches information from a blog and shows it in the app. After i fetch the data it is supposed to be shown on the table view. It shows the things that i have posted but the things are in alphabetical order rather than the time i posted the thing.
Here is the code
#implementation EventsTableViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.firstLettersArray = [NSMutableArray array];
self.eventsDictionary = [NSMutableDictionary dictionary];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self searchForEvents];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
[self searchForEvents];
}
- (void)searchForEvents
{
[self.searchBar resignFirstResponder];
NSString *eventsSearchUrlString = [NSString stringWithFormat:#"https://www.googleapis.com/blogger/v3/blogs/1562818803553764290/posts?key=AIzaSyBTOxz-vPHgzIkw9k88hDKd99ILTaXTt0Y"];
NSURL *eventsSearchUrl = [NSURL URLWithString:eventsSearchUrlString];
NSURLRequest *eventsSearchUrlRequest = [NSURLRequest requestWithURL:eventsSearchUrl];
NSURLSession *sharedUrlSession = [NSURLSession sharedSession];
NSURLSessionDataTask *searchEventsTask =
[sharedUrlSession dataTaskWithRequest:eventsSearchUrlRequest completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error)
{
dispatch_async(dispatch_get_main_queue(),
^{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
if(error)
{
UIAlertView *searchAlertView = [[UIAlertView alloc] initWithTitle:#"Error" message:error.localizedDescription delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[searchAlertView show];
}
else
{
NSString *resultString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Search results: %#", resultString);
NSError *jsonParseError = nil;
NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonParseError];
if(jsonParseError)
{
UIAlertView *jsonParseErrorAlert = [[UIAlertView alloc] initWithTitle:#"Error" message:jsonParseError.localizedDescription delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[jsonParseErrorAlert show];
}
else
{
for(NSString *key in jsonDictionary.keyEnumerator)
{
NSLog(#"First level key: %#", key);
}
[self.firstLettersArray removeAllObjects];
[self.eventsDictionary removeAllObjects];
NSArray *searchResultsArray = [jsonDictionary objectForKey:#"items"];
//NSLog(#"test%#",searchResultsArray);
for(NSDictionary *eventsInfoDictionary in searchResultsArray)
{
Events *event = [[Events alloc] init];
event.eventName = [eventsInfoDictionary objectForKey:#"title"];
event.eventDescription =[eventsInfoDictionary objectForKey:#"content"];
NSLog(#"Event Name : %#",event.eventName);
NSLog(#"Event Description : %#",event.eventDescription);
NSString *eventsFirstLetter = [event.eventName substringToIndex:1];
NSMutableArray *eventsWithFirstLetter = [self.eventsDictionary objectForKey:eventsFirstLetter];
if(!eventsWithFirstLetter)
{
eventsWithFirstLetter = [NSMutableArray array];
[self.firstLettersArray addObject:eventsFirstLetter];
}
[eventsWithFirstLetter addObject:event];
[self.eventsDictionary setObject:eventsWithFirstLetter forKey:eventsFirstLetter];
if ([event.eventDescription containsString:#"<br />"]) {
NSString* eventDescrip = event.eventDescription;
NSString* stringWithoutHTMLtags = [eventDescrip stringByReplacingOccurrencesOfString:#"<br />" withString:#""];
event.eventDescription = stringWithoutHTMLtags;
}
NSLog(#"Event Name : %#",event.eventName);
NSLog(#"Event Description : %#",event.eventDescription);
}
[self.firstLettersArray sortUsingSelector:#selector(compare:)];
[self.tableView reloadData];
}
}
});
}];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[searchEventsTask resume];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.firstLettersArray.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSString *firstLetter = [self.firstLettersArray objectAtIndex:section];
NSArray *eventsWithFirstLetter = [self.eventsDictionary objectForKey:firstLetter];
return eventsWithFirstLetter.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"eventTitleCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
NSString *firstLetter = [self.firstLettersArray objectAtIndex:indexPath.section];
NSArray *eventsWithFirstLetter = [self.eventsDictionary objectForKey:firstLetter];
Events *event = [eventsWithFirstLetter objectAtIndex:indexPath.row];
cell.textLabel.text = event.eventName;
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
/*
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString *cellText = cell.textLabel.text;
NSLog(#"Row selected %#",cellText);*/
NSString *firstLetter = [self.firstLettersArray objectAtIndex:indexPath.section];
NSArray *eventsWithFirstLetter = [self.eventsDictionary objectForKey:firstLetter];
Events *event = [eventsWithFirstLetter objectAtIndex:indexPath.row];
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
DescriptionViewController *descriptionViewController = (DescriptionViewController*)[mainStoryboard instantiateViewControllerWithIdentifier: #"descriptionController"];
descriptionViewController.eventNameDesc = event.eventDescription;
descriptionViewController.navigationItem.title = event.eventName;
[self.navigationController pushViewController:descriptionViewController animated:YES];
}
#end
You are trying to sort firstLettersArray which contain Events objects by using standard sort: function which doesn't know how to work with your custom objects.
You can use sortedArrayUsingComparator: function like this:
[firstLettersArray sortedArrayUsingComparator:^NSComparisonResult(Events *obj1, Events *obj2) {
// return object comparison result here
}];
Edit: Also you need to have NSDate property in Events class and feel it with event created time. I believe event created time should be contained in eventsInfoDictionary. Eventually you will be able to compare obj1 and obj2 using NSDate property.
i think this line not working
[self.firstLettersArray sortUsingSelector:#selector(compare:)];
use this line of code may help you....
sortedArray = [anArray sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
How to add object to NSArray with key from database?
i am using FMDatabase class to open database, its work ok, my problem is how to add object with key to NSArray, see this code
#implementation ViewController {
NSArray *allDevices;
NSArray *searchResult;
}
- (void)viewDidLoad
{
[super viewDidLoad];
FMDatabase *db = [FMDatabase databaseWithPath:[[[NSBundle mainBundle]
resourcePath] stringByAppendingPathComponent:#"db.sqlite"]];
[db open];
FMResultSet *results = [db executeQueryWithFormat:#"select * from allDevices"];
NSString *name; NSString *company;
while ([results next]) {
name = [results stringForColumn:#"name"];
company = [results stringForColumn:#"company"];
allDevices = #[
#{#"name": name, #"company": company}
];
}
[db close];
}
tableView..
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [searchResult count];
} else {
return [allDevices count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
NSDictionary *device;
if ([self.searchDisplayController isActive]) {
device = searchResult[indexPath.row];
} else {
device = allDevices[indexPath.row];
}
NSString *name = device[#"name"];
NSString *company = device[#"company"];
cell.textLabel.text = [NSString stringWithFormat:#"%# - %#", name, company];
return cell;
}
search code
#pragma mark - UISearchDisplayController delegate methods
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"name contains[cd] %#", searchText];
searchResult = [allDevices filteredArrayUsingPredicate:resultPredicate];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
its working well when i add objects to array manually, like this
allDevices = #[
#{#"name": #"iPhone", #"company": #"Apple"},
#{#"name": #"Galaxy", #"company": #"Samsung"},
#{#"name": #"iPad", #"company": #"Apple"},
];
i found it,
thanks
[allDevices addObjectsFromArray:[NSArray arrayWithObjects:[NSMutableDictionary dictionaryWithObjects:
[NSArray arrayWithObjects: rowID, name, company, nil]
forKeys:[NSArray arrayWithObjects: #"rowID", #"name", #"company", nil]], nil]];
Have a look at NSMutableDictionary.
You can do something like this:
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject: obj forKey: #"yourKey"];
where obj is the object you want to store.
Also see this post about conversion from NSDictionary to NSArray.
Now my search work by sectionsTitle, if I write "Category1" or "Category2" it find section Category1, or Category2, but I need to search by NAMES in all this sections, from here:
NSDictionary *dict = [[tableData objectForKey:[sectionsTitle objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];
[NSString stringWithFormat:#"%#", [dict objectForKey:#"Name"]];
What I need to change in my code for search by Names? Now I'm confused with all that NSArray's, NSMutableArray's and NSDictionary :(
I load my data like this:
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *path = [[documentPaths lastObject] stringByAppendingPathComponent:#"data.plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSMutableDictionary *resultDic = [[NSMutableDictionary alloc] init];
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
sectionKeys = [NSMutableArray new];
sectionsTitle = [NSMutableArray new];
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"blueKey"])
{
ann = [dict objectForKey:#"Category1"];
[resultArray addObject:#"Category1"];
[resultDic setValue:ann forKey:#"Category1"];
[sectionKeys addObject:#"Section 1"];
}
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"yellowKey"])
{
ann = [dict objectForKey:#"Category2"];
[resultArray addObject:#"Category2"];
[resultDic setValue:ann forKey:#"Category2"];
[sectionKeys addObject:#"Section 2"];
}
self.tableData = resultDic;
self.sectionsTitle = resultArray;
[myTable reloadData];
This is how I filter data:
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *resultPredicate = [NSPredicate
predicateWithFormat:#"SELF contains[cd] %#",
searchText];
searchResults = [sectionsTitle filteredArrayUsingPredicate:resultPredicate];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
This is how my table look like:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if (tableView == self.searchDisplayController.searchResultsTableView) {
return 1;
}else{
return sectionKeys.count;
}
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if (tableView == self.searchDisplayController.searchResultsTableView) {
return #"Search";
}else{
return [sectionKeys objectAtIndex:section];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [searchResults count];
} else {
int num = [[tableData objectForKey:[sectionsTitle objectAtIndex:section]] count];
return num;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
if (tableView == self.searchDisplayController.searchResultsTableView) {
cell.textLabel.text = [searchResults objectAtIndex:indexPath.row];
} else {
NSDictionary *dict = [[tableData objectForKey:[sectionsTitle objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];
cell.textLabel.font = [UIFont fontWithName:#"Avenir" size: 16.0];
cell.detailTextLabel.font = [UIFont fontWithName:#"Avenir" size: 12.0];
cell.textLabel.text = [NSString stringWithFormat:#"%#", [dict objectForKey:#"Name"]];
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#", [dict objectForKey:#"Address"]];
}
return cell;
}
My data structure:
With a simplified data set (only the Name entry included in the dictionaries), this should reproduce your setup:
NSArray *categories = #[
#[#{#"Name":#"Joe"}, #{#"Name":#"Jane"}],
#[#{#"Name":#"Anne"}, #{#"Name":#"Bob"}]
];
Then the ANY operator of NSPredicate will find the array you are after:
NSString *nameToSearch = #"Bob";
NSPredicate *catPred = [NSPredicate predicateWithFormat:#"ANY Name = %#", nameToSearch];
To see how this predicate can filter your category array:
NSArray *filteredCats = [categories filteredArrayUsingPredicate:catPred];
BTW, you might get less confused if you build some custom objects to hold your data instead of relying only on arrays and dictionaries.