sqlite search in multiple column - iphone

I have a simple database in iPad Application having couple of tables.
The UI displays the table data properly in a master-detail view controller. I want to add a search feature which will search for the given text in all the field/columns of all the tables and give the result.
One crude way is to write a select query using where clause for each columns. But I believe there will be some proper way for that.
Or is it possible to search the UITableView itself and refresh the data ?
Regards,
nirav

Code for searching in Table
- (void) searchTableView {
NSString *searchText = searchBar.text;
if([searchText length] == 0)
{
[searchArr addObjectsFromArray:userArr];
}
NSMutableArray *searchArray = [[NSMutableArray alloc] init];
for (int i=0; i<[userArr count]; i++) {
NSString *sTemp = [[userArr objectAtIndex:i] objectForKey:#"name"];
NSRange titleResultsRange = [[sTemp lowercaseString] rangeOfString:[searchText lowercaseString]];
if(titleResultsRange.location != NSNotFound && titleResultsRange.location == 0)
{
[searchArr addObject:[userArr objectAtIndex:i]];
}
}
searchArray = nil;
}

Related

Search String into NSArray based on charcters order?

My Problem Scenario is like this. I have an NSMutableArray ( Every Object is Nsstring). I have a UItextField ( as Client said) for Search.
I want know how to Search String into NSMutableArray like this
if I type A into textfield only those Content come from NSMutableArray which start From A.
if I type AB into TextField only those Content Comes from NSMutableArray which is started from AB..
....
I am Trying NSRange Concept I like share Mycode
~
for (int i=0; i<[[localTotalArrayForAwailable objectForKey:#"PUNCH"] count]; i++)
{
NSString *drinkNamePuch= [[[localTotalArrayForAwailable objectForKey:#"PUNCH"] objectAtIndex:i] drinkNames];
NSRange titleResultsRange = [drinkNamePuch rangeOfString:searchText options:( NSCaseInsensitiveSearch)];
if (titleResultsRange.length>0)
{
[searchArraypuch addObject:[[localTotalArrayForAwailable objectForKey:#"PUNCH"] objectAtIndex:i]];
[copyListOfItems setValue:searchArraypuch forKey:#"PUNCH"];
}
}
~
Based on this code search not working proper as i need.
Thanks
If you're trying to find all of the strings that match your searchText from the beginning, then you should check:
if ( titleresultsRange.location == 0 )
Other than that, I am not sure what is "not working proper", you need to provide a better explanation of what your expected results are, and what your actual results are.
Do this;
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"SELF BEGINSWITH[cd] %#", searchText];
NSArray* filteredStrings = [[localTotalArrayForAwailable objectForKey:#"PUNCH"] filteredArrayUsingPredicate:predicate];
In filteredStrings you got all the strings that begins with searchText.
You might find Predicate Programming Guide helpful.
try this logic....it is working
NSMutableArray *arr = [[NSMutableArray alloc]initWithObjects:#"aa",#"bbb",#"bb",#"cc",#"dd",#"ee",#"ff",#"gg",#"hh",#"ii", nil];
NSMutableArray *arrNew = [[NSMutableArray alloc]init];
NSString *strSearch = #"cccc";
int k = strSearch.length;
for (int i=0; i<[arr count]; i++) {
for (int j=0; j<k; j++) {
if (k<=[[arr objectAtIndex:i] length]) {
if ([strSearch characterAtIndex:j] != [[arr objectAtIndex:i]characterAtIndex:j]) {
break;
}
else if(j == k-1){
[arrNew addObject:[arr objectAtIndex:i]];
}
}
}
}
NSLog(#"%#",[arrNew description]);
You can use these methods, which are provided by NSArray/NSMutableArray:
In NSArray see section "Finding Objects in an Array" for filtering methods starting with "indexesOfObjects...", e.g. indexesOfObjectsPassingTest:
In NSArray see section "Deriving New Arrays" for the method filteredArrayUsingPredicate:
In NSMutableArray there is a method filterUsingPredicate:
For narrowing the results you can continue applying the filtering consecutively to the filtered arrays or index sets.
Example with indexesOfObjectsPassingTest: using a block:
NSArray *strings = [NSArray arrayWithObjects:#"A", #"a", #"aB", #"AbC", #"Bag", #"Babc", #"baCK", #"", #"dba", nil];
NSString *searchString = #"Ab";
BOOL (^startsWithPredicate)(id, NSUInteger, BOOL*) = ^BOOL (id obj, NSUInteger idx, BOOL *stop) {
NSString *string = (NSString *) obj;
NSRange range = [string rangeOfString:searchString options:NSCaseInsensitiveSearch];
return (range.location == 0);
};
NSIndexSet *indexSet = [strings indexesOfObjectsPassingTest:startsWithPredicate];
NSLog(#"Strings found: %#", [strings objectsAtIndexes:indexSet]);
Output:
Strings found: (
aB,
AbC
)

How to Filter Cells in AQGridView with UISearchBar

i'm going crazy on this problem:
I'm using AQGridView for show some image from an array that i retrieve from SQLite but i'm not able to filter the Grid with a UISearchBar that i put in the TitleView of a Detail zone in a SplitViewController. Can u help me with some logic passage or with an example?
Thanks!
SOLVED!
Recalculated the array _icons after removed all objects..
[_icons removeAllObjects];
searching = YES;
NSInteger numeroElem = [subcatList getSize];
for ( NSUInteger i = 0; i < numeroElem; i++ )
{
NSDictionary *itemAtIndex = (NSDictionary *)[subcatList objectAtIndex:i];
NSString *titolo_cat = [itemAtIndex objectForKey:#"titolo"];
NSComparisonResult result = [titolo_cat compare:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [searchText length])];
if (result == NSOrderedSame)
{
ETC ETC.......
[_icons addObject: image];
}
};

Suggest # tags while typing (like Twitter) for iPhone UITextView

I'd building an app that uses hashtags, like Twitter or Tweetbot. When you're typing a message, if you type the hashtag symbol, I'd like to suggest tags that match the current one you're typing.
I've already figured out how to get the UITableView to appear and show a list of hashtags, but what I can't figure out is how to do the following:
Get the NSRange of the current word being typed,
See if that range is formatted like a hashtag (NSRegularExpression #"#\\w\\w*")
(From here on out, I've got the code figured out to search for matching hashtags and show them in the UITableView)
Can anyone help me with steps 1 and 2? I've been thinking about using textViewDidChange:, but I'm concerned that the app's performance might suffer if I'm constantly running methods every time the characters change.
Thanks!
I figured it out! I wound up using the textViewDidChange: and textViewDidChangeSelection: methods.
To get the NSRange of the current hashtag being typed, I ran a for loop over the NSRegularExpression matches in the text string. From there, I used NSLocationInRange to find out if the current cursor position intersected any of the hashtags.
Here's the code:
//Get the ranges of current hashtags
NSArray *hashtagRanges = [StringChecker rangesOfHashtagsInString:textView.text];
NSTextCheckingResult *currentHashtag;
if ([hashtagRanges count] >0)
{
//List the ranges of all the hashtags
for (int i = 0; i<[hashtagRanges count]; i++)
{
NSTextCheckingResult *hashtag = [hashtagRanges objectAtIndex:i];
//Check if the currentRange intersects the hashtag
//Have to add an extra space to the range for if you're at the end of a hashtag. (since NSLocationInRange uses a < instead of <=)
NSRange currentlyTypingHashtagRange = NSMakeRange(hashtag.range.location, hashtag.range.length + 1);
if (NSLocationInRange(currentRange.location, currentlyTypingHashtagRange))
{
//If the cursor is over the hashtag, then snag that hashtag for matching purposes.
currentHashtag = hashtag;
}
}
if (currentHashtag){
//If we found one hashtag that we're currently editing
//Display the hashtag suggester, feed it the current hashtag for matching.
[self showTagTable];
//Get the current list of hashtags into an array
NSFetchRequest *hashtagRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *tagEntityDescription = [NSEntityDescription entityForName:#"Tags"
inManagedObjectContext:self.note.managedObjectContext];
[hashtagRequest setEntity:tagEntityDescription];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"dateLastUsed"
ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[hashtagRequest setSortDescriptors:sortDescriptors];
NSPredicate *tagPredicate = [NSPredicate predicateWithFormat:#"name contains[c] %#", [noteTextView.text substringWithRange:currentHashtag.range]];
[hashtagRequest setPredicate:tagPredicate];
tagsToDisplay = (NSMutableArray *)[self.note.managedObjectContext executeFetchRequest:hashtagRequest error:nil];
[tagListTable reloadData];
//If there are no matching hashtags, then let's hide the tag table.
if ([tagsToDisplay count] == 0)
{
[self hideTagTable];
return;
}
}
The StringChecker class is a custom one that I wrote, it just has class methods that parse the strings. I made StringChecker a class because the methods are used in several places in the app. Here's the method:
#pragma mark - Hashtag Methods
+(NSArray *)rangesOfHashtagsInString:(NSString *)string {
NSRegularExpression *hashtagDetector = [[NSRegularExpression alloc] initWithPattern:#"#\\w\\w*"
options:NSRegularExpressionCaseInsensitive
error:nil];
NSArray *hashtagRanges = [hashtagDetector matchesInString:string
options:NSMatchingWithoutAnchoringBounds
range:NSMakeRange(0, string.length)];
return hashtagRanges;
}
+(NSUInteger)numberOfHashtagsInString:(NSString *)string {
NSRegularExpression *hashtagDetector = [[NSRegularExpression alloc] initWithPattern:#"#\\w\\w*"
options:NSRegularExpressionCaseInsensitive
error:nil];
NSUInteger numberOfHashtags = [hashtagDetector numberOfMatchesInString:string
options:NSRegularExpressionCaseInsensitive
range:NSMakeRange(0, string.length)];
return numberOfHashtags;
}
Another way I figured out to do this is as follows.
In the - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text function I put a listener for a # being typed which begins recording the characters following the hash until the user types a space at which time it resets.
if ([text isEqualToString:#"#"]) {
recordingHashTag = YES;
startParse = range.location;
}else if ([text isEqualToString:#" "]) {
currentHashTag = nil;
recordingHashTag = NO;
theTable.hidden = YES;
}
if (recordingHashTag == YES) {
NSString *value;
if (startParse > [textView.text length] - startParse) {
value = [textView.text substringWithRange:NSMakeRange(startParse, [textView.text length] - startParse)];
[self filterHashTagTableWithHash:value];
}
}
If the BOOL recordingHashTag is set to YES I pass the substring containing the hashtag text to a function which searches a pre populated array of hashtags. If there is a match it adds that entry to a filtered array of hashtags which it uses to populate the tableview on the fly.
-(void)filterHashTagTableWithHash:(NSString *)hash{
[self.filterHashTagArray removeAllObjects];
for (NSString *hashTag in self.hashTagArray ){
NSRange result = [hashTag rangeOfString:hash options:NSCaseInsensitiveSearch];
if (result.location != NSNotFound) {
[filterHashTagArray addObject:hashTag];
}
}
if (filterHashTagArray.count) {
theTable.hidden = NO;
}else{
theTable.hidden = YES;
}
[self.theTable reloadData];
}
The final step is to insert the hash tag when the user clicks on the entry in the table.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = (UITableViewCell*)[self tableView:theTable cellForRowAtIndexPath:indexPath];
NSString *newString = [textViewComment.text stringByReplacingCharactersInRange:NSMakeRange(startParse, [textViewComment.text length] - startParse) withString:cell.textLabel.text];
textViewComment.text = newString;
}
Just don't forget to clear out your variables when a user backspaces mid hash tag.

How to implement UITableView search functionality

My iPhone application has a UITable View implemented with search functionality in it. The values in the table are grouped into sections from A-Z. Whenever a user tap on particular cell in the table it loads a detail view controller which gives all the values of that particular user. Now my problem is whenever I search some contact and tap on a particular user to check his detail view it always returns a contact starting with letter A. So, my doubt is how to implement this search functionality. Is there a way to get the name of the contact I tapped..Please check this screenshot.. For example if I search some contact starting with letter 'B' and tap on that contact it loads the detail view of a contact starting with letter 'A'. I get all the values from the database. Can you please help me out...
This is the code:
The code I wrote here is in a method:
I am getting all the contacts from database and assigning to an array contacts. Then I am grouping all the contacts according to the alphabets and grouping everything into a dictionary with keys as A-Z and values as name of contacts starting with these letters. Now when I search for a particular contact his name may start with either A ,B or Z..so in the search bar when I search for a particular contact for example a contact starting with letter Z, in this case it gives the details of a person with A. I want this to change so that whenever I tap on a particular contact it should load its details. I am unable to figure out how to do it..
contacts = [[db getContacts:#"Contacts"] componentsSeparatedByString:#","];
[db cleanup];
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
NSString *charString;
for (int i=65; i<91; i++) {
charString = [NSString stringWithFormat:#"%c",(char *)i];
[tempArray addObject:charString];
}
[charString release];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
for (int i=0; i<[tempArray count]; i++) {
NSMutableArray *contactsByIndex = [[[NSMutableArray alloc] init]autorelease];
NSString *tempChar = [tempArray objectAtIndex:i];
for (int j=0; j<[contacts count]-1; j++)
{
NSString *test = [contacts objectAtIndex:j];
NSString *tempString = [test substringToIndex:1];
if ([tempString isEqualToString:tempChar]) {
[contactsByIndex addObject:[contacts objectAtIndex:j]];
}
}
[dict setObject:contactsByIndex forKey:[tempArray objectAtIndex:i]];
}
self.contactNames = dict;
NSArray *array = [[contactNames allKeys] sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
self.contactKeys = array;
[dict release];
[tempArray release];
//---display the searchbar---
self.tableView.tableHeaderView = searchBar;
searchBar.autocorrectionType = UITextAutocorrectionTypeYes;
listOfContacts = [[NSMutableArray alloc] init];
for (NSString *key in array)
{
NSArray *contactsArray = [contactNames objectForKey:key];
for (NSString *name in contactsArray) {
[listOfContacts addObject:name];
}
}
- (void) searchContactsTableView {
//---clears the search result---
[searchResult removeAllObjects];
for (NSString *str in listOfContacts) {
NSRange titleResultsRange = [str rangeOfString:searchBar.text options:NSCaseInsensitiveSearch];
if (titleResultsRange.length > 0)
[searchResult addObject:str];
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here. Create and push another view controller.
NSString *selectedRow=nil;
if (isSearchOn) {
selectedRow=[searchResult objectAtIndex:indexPath.row];
}
DetailViewController *detailViewController;
int section_index=[indexPath indexAtPosition:[indexPath length]-2];
int sugarid_Index = [indexPath indexAtPosition: [indexPath length]-1];
NSString* sectionName=[contactKeys objectAtIndex:section_index];
NSLog(#"%#",sectionName);
//This is a method which gets the details of a particular contact based on the section and the row selected..Contacts is the table name
NSString *getContact=[db getId:#"Contacts" bySection:sectionName andIndex:sugarid_Index];
id=[db getContact:#"Contacts" id:getContact];
// Pass the selected object to the new view controller.
detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
detailViewController.eachContact=contactForSugarId;
[self.navigationController pushViewController:detailViewController animated:YES];
}
When I search for a contact it should search for the name in database and should return its details. Is there a way to do it..please let me know or is there a way to get the name of the cell i.e. the contact name so that I can use that in one of my database methods to retrieve the details of the contact I selected.
Off hand it sounds like you're looking in the wrong array of contacts after the search. You need to have two arrays. One with all the contacts, and one with the filtered contacts. When you search, put all the results in order in the filtered list, and pull the details from that one.
Does this make sense?
If not, try posting a bit of code, and explaining your structure.

Adding # & search sign to TableIndex in UITableView

In iPhone native Phone book - there is a search character at the top & # character at the bottom.
I want to add both of that character in my table Index.
Currently I have implemented following code.
atoz=[[NSMutableArray alloc] init];
for(int i=0;i<26;i++){
[atoz addObject:[NSString stringWithFormat:#"%c",i+65]];
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView{
return atoz;
}
How to have # character & search symbol in my UITableView?
The best way to tackle this is to make use of the tools the framework provides. In this case, you want to use UILocalizedIndexedCollation (developer link).
I also have a decorator for this class that is designed to insert the {{search}} icon for you and handle the offsets. It is a like-for-like drop-in replacement for UILocalizedIndexedCollation.
I've posted a more in-depth description of how to use this on my blog. The decorator is available here (Gist).
The basic idea is to group your collection into an array of arrays, with each array representing a section. You can use UILocalizedIndexedCollation (or my replacement) to do this. Here's a small NSArray category method I use to do this:
#implementation NSArray (Indexing)
- (NSArray *)indexUsingCollation:(UILocalizedIndexedCollation *)collation withSelector:(SEL)selector;
{
NSMutableArray *indexedCollection;
NSInteger index, sectionTitlesCount = [[collation sectionTitles] count];
indexedCollection = [[NSMutableArray alloc] initWithCapacity:sectionTitlesCount];
for (index = 0; index < sectionTitlesCount; index++) {
NSMutableArray *array = [[NSMutableArray alloc] init];
[indexedCollection addObject:array];
[array release];
}
// Segregate the data into the appropriate section
for (id object in self) {
NSInteger sectionNumber = [collation sectionForObject:object collationStringSelector:selector];
[[indexedCollection objectAtIndex:sectionNumber] addObject:object];
}
// Now that all the data's in place, each section array needs to be sorted.
for (index = 0; index < sectionTitlesCount; index++) {
NSMutableArray *arrayForSection = [indexedCollection objectAtIndex:index];
NSArray *sortedArray = [collation sortedArrayFromArray:arrayForSection collationStringSelector:selector];
[indexedCollection replaceObjectAtIndex:index withObject:sortedArray];
}
NSArray *immutableCollection = [indexedCollection copy];
[indexedCollection release];
return [immutableCollection autorelease];
}
#end
So, given an array of objects, for example books that I want to divide into sections based on their name (the Book class has a name method), I would do this:
NSArray *books = [self getBooks]; // etc...
UILocalizedIndexedCollation *collation = [UILocalizedIndexedCollation currentCollation];
NSArray *indexedBooks = [books indexUsingCollation:collation withSelector:#selector(name)];