search method not working after second hit - objective-c

I've a problem with my UISearchDisplayController, the search is not working properly.
This is my code:
- (void)filterContentForSearchText:(NSString*)searchText
scope:(NSString*)scope
{
[self.searchResults removeAllObjects];
for (int i = 0; i < [temp_category count]; i++) {
BOOL foundResult = FALSE;
if ([[temp_category objectAtIndex:i] rangeOfString:searchText].location != NSNotFound) {
foundResult = TRUE;
}
if ([[price_producttitle objectAtIndex:i] rangeOfString:searchText].location != NSNotFound) {
foundResult = TRUE;
}
if ([[price_type objectAtIndex:i] rangeOfString:searchText].location != NSNotFound) {
foundResult = TRUE;
}
if ([[price_description objectAtIndex:i] rangeOfString:searchText].location != NSNotFound) {
foundResult = TRUE;
}
if (foundResult) {
NSNumber *result = [NSNumber numberWithInt:i];
if ([self searchResults] == nil) {
NSMutableArray *array = [[NSMutableArray alloc] init];
[self setSearchResults:array];
[array release];
}
[searchResults addObject:result];
}
}
NSLog (#"array = %i", [searchResults count]);
NSLog(#"%#",searchResults);
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchScope:(NSInteger)searchOption
{
[self filterContentForSearchText:[self.searchDisplayController.searchBar text]
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:searchOption]];
return YES;
}
But I'm still confused, because when I start a search with the first letter, it gives the correct hits. But when I enter the second letter, it only shows one result (while there are more, as far as I know from my data sample). I'm doing something incorrectly. I think it has something to do with when the user enters text, but I'm confused which method I should use.
The code I now have is a combination of:
this tutorial and
this SO question.
Can someone give me a hint in the good direction? Displaying the results is fine, only this aspect bothers me. I think it has something to do with firing the method and [self.searchResults removeAllObjects];.

I would like to add my code, but the thing is that I still use the code I have above, but I'm manually implementing the UISearchBar (which I found somewhere else in a tutorial) instead of using SearchDisplayController. I also had difficulties with the navigationbar which dissappears when using SearchDisplayController, which gave me enough reason to implement it myself instead of using SearchDisplayController. It gives you more freedom.
At first it seemed a lot of work, so I choose to use SearchDisplayController, but I really advise anyone who needs some modification, or who wants more freedom, please do it manually with UISearchBar and a UITableView :)

Related

function to check if there is any empty cell in a multicolumn nstableview not working

Hi i have written a function to check if there is any empty cell in a multicolumn nstableview like below.However this function is not working and always checks for the columns in the first row only.. any suggestions.and what is the right way to check for it
-(BOOL)isTableRowsContainingEmptyCells
{
for(int row=0;row< [[self.myarray arrangedObjects] count];row++)
{
NSTableColumn *column1 = [self.formFieldValues
tableColumnWithIdentifier:#"A"];
NSTableColumn *column2 = [self.formFieldValues
tableColumnWithIdentifier:#"B"];
NSCell *cell1 = [column1 dataCellForRow:row];
NSCell *cell2 = [column2 dataCellForRow:row];
NSLog(#"cell1 %# cell2 %#",cell1,cell2);
if([[cell1 stringValue] isEqualToString:#""]||[cell1 stringValue]==nil||[[cell2 stringValue] isEqualToString:#""]||[cell2 stringValue]==nil)
{
return YES;
}
}
return NO;
}
Try like this
NSCell *cll=[tableView preparedCellAtColumn:0 row:0];
NSString *str=[cll stringValue];
NSInteger len=[str length];
if (len ==0)
{
NSLog(#"NO data")
}

ARC conversion issue with handleSearchForTerm delegate method

since converting to ARC (automatically) i have noticed with my uisearchviewcontroller delegate an issue somewhere (i think in the first if statement below). It was changed as a result but either way my app crashes when i try to perform a search:
The current code:
[self setSavedSearchTerm:searchTerm];
if ([self searchResults] == nil)
{
NSMutableArray *array = [[NSMutableArray alloc] init];
[self setSearchResults:array];
array = nil;
}
[[self searchResults] removeAllObjects];
if ([[self savedSearchTerm] length] != 0)
{
for (KABrand *currentBrand in [self brands])
{
if ([currentBrand.name rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location != NSNotFound)
{
if (![searchResults containsObject:currentBrand])
[[self searchResults] addObject:currentBrand];
}
}
}
The previous code:
- (void)handleSearchForTerm:(NSString *)searchTerm
{
[self setSavedSearchTerm:searchTerm];
if ([self searchResults] == nil)
{
NSMutableArray *array = [[NSMutableArray alloc] init];
[self setSearchResults:array];
[array release], array = nil;
}
[[self searchResults] removeAllObjects];
if ([[self savedSearchTerm] length] != 0)
{
for (KABrand *currentBrand in [self brands])
{
if ([currentBrand.name rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location != NSNotFound)
{
if (![searchResults containsObject:currentBrand])
[[self searchResults] addObject:currentBrand];
}
}
}
}
Thanks for your help in advance!
Thanks guys
Here is one potential problem: -rangeOfString:options: may return an NSNotFound. But you are checking if the range.location != NSNotFound.
If is if the return value of -rangeOfString:options: is NSNotFound, your if statement becomes NSNotFound.location != NSNotFound. I don't believe that's allowed.

cancel button on search bar does not cancel correctly

I have a search bar, i can search now, but when I enter a text to search, and click the cancel button. It does not give me back my first stage, meaning full of the items in the table.
For example: I search the item with word: a, it gives me all the a items, yes, it is right now, but when i hit the cancel button, i want the programme gives me all the items exist, not just a items.
Here is the code: please help me out. Thank you so much.
- (void)searchBarCancelButtonClicked:(UISearchBar *)aSearchBar
{
searchBar.text = #"";
[searchBar resignFirstResponder];
letUserSelectRow = YES;
searching = NO;
self.tableView.scrollEnabled = YES;
NSLog(#"what text after cancel now: %#", searchBar.text);
[self.tableView reloadData];
}
- (NSMutableArray *) searchTableView {
NSString *searchText = searchBar.text;
NSLog(#"search text: %#", searchText);
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
NSMutableArray *tempArr = [[NSMutableArray alloc] init];
for (NSDictionary *dTemp in arrayData)
{
NSString *tempStr = [dTemp objectForKey:#"url"];
NSLog(#"sTemp string: %#",[ NSString stringWithFormat:#"%#", tempStr]);
NSRange titleResultsRange = [tempStr rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (titleResultsRange.length > 0)
{
NSLog(#"1 count :%d", [resultArray count]);
[resultArray addObject:dTemp];
NSLog(#"2 count :%d", [resultArray count]);
[tempArr addObject:resultArray];
[resultArray release];
resultArray = [NSMutableArray new];
}
}
if (resultArray != nil) {
[resultArray release];
}
return tempArr;
}
- (void)searchBar:(UISearchBar *)aSearchBar textDidChange:(NSString *)searchText
{
NSLog(#"what text after cancel now: %#", searchBar.text);
if([searchText length] > 0) {
[sortedArray removeAllObjects];
searching = YES;
letUserSelectRow = YES;
self.tableView.scrollEnabled = YES;
NSMutableArray *searchArray = [self searchTableView];
sortedArray = [[NSMutableArray alloc] initWithArray:searchArray copyItems:YES];
for (int i = 0; i<[sortedArray count]; i++) {
NSLog(#"this is the search array: %#", [[sortedArray objectAtIndex:i] class]);
}
NSLog(#"sorted array: %d", [sortedArray count]);
}
else {
searching = NO;
letUserSelectRow = NO;
self.tableView.scrollEnabled = NO;
}
[self.tableView reloadData];
}
You don't need to override any of UISearchBar methods to accomplish this. The new way of doing this relies on the UISearchDisplay controller instead (specifically on shouldReloadTableForSearchString).
Declare your view controller to conform to UISearchDisplayDelegate protocol, and keep two instance variables: your model as NSArray (all data) and a filtered array as NSMutableArray (a subset of your data). The code you presently have in "searchTableView" would filter the content of the model and place it into the filtered NSMutableArray. Then you would override the following UITableView methods: -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section and -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath. In each, before returning, make a comparison to determine whether your tableView argument is equal to self.searchDisplayController.searchResultsTableView. If it is, the user is looking at the filtered list and your should use the content of the filtered NSMutableArray to create the view, otherwise, the user is looking at the whole data set and you should use the content of the NSArray that holds your model. Take a look at the following Apple code for a simple example of what I described:
http://developer.apple.com/library/ios/#samplecode/TableSearch/Introduction/Intro.html

CS193P - Adding floating point button to iOS calculator

I recently started following the online course on iPhone development from Stanford University on iTunes U.
I'm trying to do the homework assignments now for the first couple of lectures. I followed through the walkthrough where I built a basic calculator, but now I'm trying the first assignment and I can't seem to work it out. It's a follows:
Your calculator already works with floating point numbers (e.g. if you press 3 / 4 =
it will properly show the resulting value of 0.75), however, there is no way for the user
to enter a floating point number. Remedy this. Allow only legal floating point
numbers to be entered (e.g. “192.168.0.1” is not a legal floating point number).
First of all, I'm not sure whether a floating point counts as digitPressed or operationPressed. I even tried with a new method called floatingPointPressed but that didn't really work out. Could someone provide pointers on this?
When I saw it as digitPressed, I tried something like this:
if (hasFloatingPoint) {
NSRange range = [[display text] rangeOfString:#"."];
if (range.location == NSNotFound)
{
[display setText:[[display text] stringByAppendingFormat:digit]];
hasFloatingPoint = YES;
}
}
else {
[display setText:[[display text] stringByAppendingFormat:digit]];
}
But I'm missing the key concept here, I think.
I have also tried another solution which I have, sadly, undone already so I can't provide the code but what happend was this: I could press a number, say 5 and then a floating point and 3 so I would end up with 5.3. I then managed to 'disable' the floating point for the remainder of the input.. But I guess I was a little too strict on it: I couldn't, for example, put in 5.3.2 but after pressing an operation button (+, etc), it still wouldn't let me press the floating point button. I guess I should reset the bool I used for this?
I'm not looking for a completely written out solution here, but could someone be so kind to provide some basic advice on how to tackle this problem? Some kind of step-by-step overview of what I should do and think about, without actually providing a code solution.
Thanks in advance.
Okay. I solved this. Was fairly easy once I managed to wrap my head around it:
-(IBAction)digitPressed:(UIButton *)sender
{
NSString *digit = [[sender titleLabel] text];
NSRange range = [[display text] rangeOfString:#"."];
if (userIsInTheMiddleOfTypingANumber)
{
if ( ! ([digit isEqual:#"."] && (range.location != NSNotFound))) {
[display setText:[[display text] stringByAppendingFormat:digit]];
}
}
else
{
if ([digit isEqual:#"."]) {
[display setText: #"0."];
}
else {
[display setText: digit];
}
userIsInTheMiddleOfTypingANumber = YES;
}
}
Since you want a hint of where to look, have a look at attaching a NSNumberFormatter to the input fields.
This is the proper way of validating input, rather than manually checking each character the user enters yourself.
edit
I've just read the assignment that you are trying to work through. I think my answer here, although still the right way to do it, not the best way to do what the assignment is trying to get you to do.
Since you are reading the digits one by one as they are added to the view and appending them to the number you are operating on you may be on the right track with your original answer:
Keep accepting numbers as they are added
Add a decimalEntered flag - initialise it to 'NO'
If a decimal is entered, check the flag, if it is no, accept it and set the flag to YES
If a decimal is entered and the flag is YES, don't accept it.
Whenever you press an operand, set this flag back to NO.
When you learn a bit more, you'll realise that another way to do this is to let the user type in the field. Hook up a formatter to the field to validate that the input is a valid number, but it will also be able to turn the string into a number for you. And when an operand is pressed, this number will be kept aside as one of the numbers upon which the operand will operate.
-(IBAction)floatingPoint:(UIButton *)sender {
NSString *digit = sender.currentTitle;
NSRange range = [self.display.text rangeOfString:#"."];
if(range.location == NSNotFound){
self.display.text = [self.display.text stringByAppendingString:digit];
self.userIsInTheMiddleOfEnteringANumber = YES;
}
}
Your can also use scanners to solve this problem. The code is simpler and I think it also localized.
if (userIsInTheMiddleOfTypingANumber) {
// Allow floating point numbers to be input. Malformed numbers are replaced by 0
NSScanner *scanner = [NSScanner scannerWithString:display.text];
double d;
BOOL wellFormedDouble = [scanner scanDouble:&d];
if (wellFormedDouble && [scanner isAtEnd]) {
brain.operand=d;
}
else {
brain.operand=0;
}
userIsInTheMiddleOfTypingANumber = NO;
}
Hey I think I have a simple solution that works :)
- (IBAction)digitPressed:(UIButton *)sender
{
NSString *digit = [[sender titleLabel] text];
NSRange range = [[display text] rangeOfString:#"."];
if (range.location != NSNotFound && [digit isEqual:#"."]) {
return;
}
if (userIsInTheMiddleOfTypingANumber)
{
[display setText:[[display text] stringByAppendingString:digit]];
}
else
{
[display setText:[digit isEqual:#"."] ? #"0." : digit];
userIsInTheMiddleOfTypingANumber = YES;
}
}
i saw that it suggests to add a function to handle the decimal after i started in on that bit, and ended up with this. the decimal flag is reset in operation pressed. and to really complete it, it should probably disallow leading 0's too.
if (userIsInTheMiddleOfTypingANumber) {
if ([digit isEqual:#"."]) {
if (!userIsInTheMiddleOfTypingADecimal) {
[display setText:[[display text] stringByAppendingString:digit]];
userIsInTheMiddleOfTypingADecimal = YES;
}
}else {
[display setText:[[display text] stringByAppendingString:digit]];
}
}
else//new number
{
if ([digit isEqual:#"."]) {
if (!userIsInTheMiddleOfTypingADecimal) {// this is a superfluous check as if it's a new number it is also not a decimal.
[display setText:#"0."];
userIsInTheMiddleOfTypingADecimal = YES;
userIsInTheMiddleOfTypingANumber = YES;
}
}else {
[display setText:digit];
userIsInTheMiddleOfTypingANumber = YES;
}
}
I found that I did not need to use NSRange. My code can do the operations beginning with a decimal number or a floating number.
-(IBAction)digitPressed:(UIButton *)sender
{
NSString *digit = [[sender titleLabel] text];
if(userIsInTheMiddleOfTypingANumber)
{
[display setText:[[display text] stringByAppendingFormat:digit]];
}
else
{
if([digit isEqual:#"."]) //check for the decimal and append to the digits
[display setText:#"."];
else
[display setText:digit];
userIsInTheMiddleOfTypingANumber = YES;
}
}
I couldn't get any of the above code to work with the CS193P Fall 2011 Calculator.
Here is how I finally got it to work.
-(IBAction)digitPressed:(UIButton *)sender
{ // Begin ACTION
NSString *digit = sender.currentTitle;
if (self.userIsInTheMiddleOfEnteringNumber)
{
//Check to see if a decimal was entered
if ([digit isEqual:#"."])
{
//Check to see if a decimal was entered before
if (self.decimalEntered)
{
[self Display];
}
else
{
self.Display.text = [self.Display.text stringByAppendingString: digit];
self.decimalEntered = YES;
}
}
else
{
self.Display.text = [self.Display.text stringByAppendingString: digit];
}
}
else
{
if ([digit isEqual:#"."])
{
//First Decimal Entered";
self.Display.text = digit;
self.decimalEntered = YES;
}
else
{
//First Number Entered";
self.Display.text = digit;
}
// This tells the Brain that the user is typing
self.userIsInTheMiddleOfEnteringNumber = YES;
}
} // End ACTION
I believe this is simpler.
- (IBAction)digitPressed:(UIButton *)sender
{
NSString *digit =[[sender titleLabel] text];
NSRange range =[[display text] rangeOfString:#"."];
if (([digit isEqual:#"."])&&(range.location==NSNotFound)){midtype=YES;}
if (midtype){
if (([digit isEqual:#"."])&&(range.location!=NSNotFound))
{[display setText:[display text]];}
else {[display setText:[[display text]stringByAppendingString:digit]];}
}
else {[display setText:digit];
midtype =YES;
}
}
This is my first solution and doesn't look objective-C style but it works...
- (IBAction)digitPressed:(UIButton *)sender
{
NSString *digit = [sender currentTitle];
if ([digit isEqualToString:#"."]) {
self.numberOfDot ++;
}
if (self.userIsInTheMiddleOfEnteringANumber){
if (self.numberOfDot < 2) {
self.display.text = [self.display.text stringByAppendingString:digit];
}
else
if (![digit isEqualToString:#"."])
self.display.text = [self.display.text stringByAppendingString:digit];
}
else {
self.display.text = digit;
self.userIsInTheMiddleOfEnteringANumber = YES;
}
}

UITableView and SearchBar problem

I'm trying to add a Search bar to my UITableView. I followed this tutorial: http://clingingtoideas.blogspot.com/2010/02/uitableview-how-to-part-2-search.html.
I'm getting this error if I type a letter in the search box: Rooster(10787,0xa05ed4e0) malloc: *** error for object 0x3b5f160: double free
*** set a breakpoint in malloc_error_break to debug.
This error occurs here:
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self handleSearchForTerm:searchString];
return YES;
}
(on the second line)
- (void)handleSearchForTerm:(NSString *)searchTerm {
[self setSavedSearchTerm:searchTerm];
if ([self searchResults] == nil) {
NSMutableArray *array = [[NSMutableArray alloc] init];
[self setSearchResults:array];
[array release];
}
//Empty the searchResults array
[[self searchResults] removeAllObjects];
//Check if the searchTerm doesn't equal zero...
if ([[self savedSearchTerm] length] != 0) {
//Search the whole tableList (datasource)
for (NSString *currentString in tableList) {
NSString *klasString = [[NSString alloc] init];
NSInteger i = [[leerlingNaarKlasList objectAtIndex:[tableList indexOfObject:currentString]] integerValue];
if(i != -1) {
klasString = [klassenList objectAtIndex:(i - 1)];
}
//Check if the string matched or the klas (group of school)
if ([currentString rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location != NSNotFound ||
[klasString rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location != NSNotFound) {
//Add to results
[[self searchResults] addObject:currentString];
//Save the klas (group of school). It has the same index as the result (lastname)
NSString *strI = [[NSString alloc] initWithFormat:#"%i", i];
[[self searchResultsLeerlingNaarKlas] addObject:strI];
[strI release];
}
[klasString release];
}
}
}
Can someone help me out?
Regards,
Dodo
The double free error means you have released an object more than needed. Here the suspicious object is klasString.
From your code:
NSString *klasString = [[NSString alloc] init];
...
if(i != -1) {
klasString = [klassenList objectAtIndex:(i - 1)];
}
...
[klasString release];
The assignment inside the if statement
loses reference to the newly allocated NSString, introducing a memory leak
makes the later release apply to the object from klassenList. When klassenList releases its elements, a double free error will occur.