p2p.wrox.com Forums

p2p.wrox.com Forums (http://p2p.wrox.com/index.php)
-   BOOK: Professional iPhone and iPad Database Application Programming (http://p2p.wrox.com/forumdisplay.php?f=603)
-   -   search crashing (http://p2p.wrox.com/showthread.php?t=87149)

Jule April 2nd, 2012 01:38 AM

search crashing
 
Chapter 3 implementing the search, code builds great, loads with no errors and succeeded.

Main screen loads and list is loaded in alphabetical order and can go to next screen view, but when I go to use the search bar the app closes and goes to main screen. I have checked my code against sample and appears to be ok. But I think I may have missed something.

Any pointers where to look. Searching is what I need most to work. :(


If you need my code let me know.

thepianoguy April 2nd, 2012 11:01 AM

Will need to see code to diagnose.
Send the nonworking project to
ipadhelper@me.com

and I should be able to sort it out.

Bob

Jule April 4th, 2012 01:05 AM

Working Code
 
I decided to have one final attempt at this before troubling ThePianoGuy. Started from Scratch, the code worked. No crashing no problems every great.

Checked code against non working project, found a typo used a instead of @, but it still won't work. Copied and pasted new project into old and works like a charm.

Still can't see where I went wrong. If anyone is bored and wants to try

here is non-working code

Code:


#import "RootViewController.h"


@implementation RootViewController

@synthesize croplists;
@synthesize filteredCrops;
@synthesize searchBar;
@synthesize searchController;



- (void)viewDidLoad {
    [super viewDidLoad];
       
        self.croplists = [NSMutableArray arrayWithCapacity:1];
       
        NSMutableArray *croplistsTemp;
       
        // get the DBAccess object
        DBAccess *dbAccess = [[DBAccess alloc] init];
       
        // get the array from the database
        croplistsTemp = [dbAccess getAllCropLists];
       
        // close the database finished with it
        [dbAccess closeDatabase];
       
        // release the dbAccess object to free its memory
        [dbAccess release];
       
    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem;

        UILocalizedIndexedCollation *indexedCollation = [UILocalizedIndexedCollation currentCollation];
       
        // iterate over the crops, populating their section number
        for (CropList *theCropList in croplistsTemp) {
                NSInteger section = [indexedCollation sectionForObject:theCropList collationStringSelector:@selector(name)];
                theCropList.section = section;
                       
        }
       
        // get the count of the number of sections
        NSInteger sectionCount = [[indexedCollation sectionTitles] count];

        // create an array to hold the sub arrays
        NSMutableArray *sectionsArray = [NSMutableArray arrayWithCapacity:sectionCount];
       
        // interate over each section, creating each sub array
        for (int i=0; i<=sectionCount; i++) {
                NSMutableArray *singleSectionArray = [NSMutableArray arrayWithCapacity:1];
                [sectionsArray addObject:singleSectionArray];
        }
       
        // iterate over the crops putting each crop into the correct sub-array
        for (CropList *theCropList in croplistsTemp) {
                [(NSMutableArray *) [sectionsArray objectAtIndex:theCropList.section] addObject:theCropList];
        }
       
        // iterate over each section array to sort the items in the section
        for (NSMutableArray *singleSectionArray in sectionsArray) {
                // use the UILocalizedIndexedCollation sortedArrayFromArray: method to sort each array
                NSArray *sortedSection = [indexedCollation sortedArrayFromArray:singleSectionArray collationStringSelector:@selector(name)];
                [self.croplists addObject:sortedSection];
        }
       
        // create search bar
        self.searchBar = [[[UISearchBar alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 44.0f)] autorelease];
        self.tableView.tableHeaderView = self.searchBar;
       
        // create and configure the search controller
        self.searchController = [[[UISearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self] autorelease];
        self.searchController.searchResultsDataSource = self;
        self.searchController.searchResultsDelegate = self;
       
}       

       
/*
 - (void)viewWillAppear:(BOOL)animated {
 [super viewWillAppear:animated];
 }
 */
/*
 - (void)viewDidAppear:(BOOL)animated {
 [super viewDidAppear:animated];
 }
 */
/*
 - (void)viewWillDisappear:(BOOL)animated {
 [super viewWillDisappear:animated];
 }
 */
/*
 - (void)viewDidDisappear:(BOOL)animated {
 [super viewDidDisappear:animated];
 }
 */


 // Override to allow orientations other than the default portrait orientation.
 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
 // Return YES for supported orientations.
        return YES; //(interfaceOrientation == UIInterfaceOrientationPortrait);
 }



#pragma mark Table view methods

// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
        // is the request for numberOfRowsInSection for the regular table?
        if (tableView == self.tableView)
        {
                // return the count of the crops as normal
                return [self.croplists count];
        }
        return 1;
}


// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        // is the request for numberOfRowsInSection for the regular table?
        if (tableView == self.tableView)
        {
                // just return the count of the crops as normal
                return [[self.croplists objectAtIndex:section] count];
        }
                // count for the filtered table
                // first, flatten the array of arrays self.croplists
                NSMutableArray *flattenedArray = [[NSMutableArray alloc] initWithCapacity:1];
                for (NSMutableArray *theArray in self.croplists)
                {
                        for (int i=0; i<[theArray count]; i++)
                        {
                                [flattenedArray addObject:[theArray objectAtIndex:i]];
                        }
               
                }
       
        // setup the NSPredicate to filter the rows
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name begins with[c] %@", self.searchBar.text];
        self.filteredCrops = [flattenedArray filteredArrayUsingPredicate:predicate];
       
        // clean up flattened array
        [flattenedArray release];
       
        return self.filteredCrops.count;
                                 
}
                                 

// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";
   
    CropTableViewCell *cell = (CropTableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[CropTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }
   
        // Configure the cell.
        cell.accessoryType = UITableViewCellAccessoryNone;
       
        // is the request for cellForRowAtIndexPath for the regular path?
        if (tableView == self.tableView)
        {
               
                // get the crop object
                CropList *croplist = [[self.croplists objectAtIndex:[indexPath section]] objectAtIndex:[indexPath row]];
       
                // set the crop to be used to draw the cell
                [cell setCropList:croplist];
       
                return cell;
        }
       
        // get the crop object
        CropList *croplist = [self.filteredCrops objectAtIndex:[indexPath row]];
        // set the crop to be used to draw the cell
        [cell setCropList:croplist];
       
        return cell;
}

       
// override to support row selection in the table view       
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {       
               
        // get the crop that corresponds with the cell selected
        CropList *croplist;
               
        if (tableView == self.tableView)
        {
                // get the crop that corresponds with the touched cell
                croplist = [[self.croplists objectAtIndex:[indexPath section]] objectAtIndex:[indexPath row]];
    }
                                         
    else {
                croplist = [self.filteredCrops objectAtIndex:[indexPath row]];
    }
                                         
         
  //initialise detail view controller from the NIB xib file
  CropListDetailViewController *cropListDetailViewController = [[CropListDetailViewController alloc] initWithNibName:@"CropListDetailViewController" bundle:nil];
                                         
  // set titles of detail page
  [cropListDetailViewController setTitle:croplist.name];
                                         
  // push detail controller to the stack
  [self.navigationController pushViewController:cropListDetailViewController animated:YES];
                                         
  // populate the details
  [cropListDetailViewController setLabelsForCropList:croplist];
                                         
  // release the view controller
  [cropListDetailViewController release];
                                         
}   
                                         
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
        // make sure that the section will contain some data
        if ([[self.croplists objectAtIndex:section] count] >0) {
               
                // if it does, get the section title from the UILocalizedIndexedCollation object
                return [[[UILocalizedIndexedCollation currentCollation] sectionTitles] objectAtIndex:section];
        }
        return nil;
}

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
        if (tableView == self.tableView)
        {
               
                // setup the index titles from the UILocaliszedIndexedCollation
                return [[UILocalizedIndexedCollation currentCollation] sectionIndexTitles];
        }
        return nil;
}
       
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex: (NSInteger)index {
        // link the sections to the labels in the table
        return [[UILocalizedIndexedCollation currentCollation] sectionForSectionIndexTitleAtIndex:index];
}
       

/*
 // Override to support conditional editing of the table view.
 - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
 // Return NO if you do not want the specified item to be editable.
 return YES;
 }
 */


/*
 // Override to support editing the table view.
 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
 
 if (editingStyle == UITableViewCellEditingStyleDelete) {
 // Delete the row from the data source.
 [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
 } 
 else if (editingStyle == UITableViewCellEditingStyleInsert) {
 // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
 } 
 }
 */


/*
 // Override to support rearranging the table view.
 - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
 }
 */


/*
 // Override to support conditional rearranging of the table view.
 - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
 // Return NO if you do not want the item to be re-orderable.
 return YES;
 }
 */

#pragma mark -
#pragma mark Memory Management

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
   
    // Relinquish ownership any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
    // Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
    // For example: self.myOutlet = nil;
}



- (void)dealloc {
       
  [super dealloc];
       
}
                                 


@end

and the working code

Code:


#import "RootViewController.h"


@implementation RootViewController

@synthesize croplists;
@synthesize filteredCrops;
@synthesize searchBar;
@synthesize searchController;



#pragma mark -
#pragma mark View lifecycle


- (void)viewDidLoad {
    [super viewDidLoad];
       
        self.croplists = [NSMutableArray arrayWithCapacity:1];
       
        NSMutableArray *croplistsTemp;
       
        // get the DBAccess object
        DBAccess *dbAccess = [[DBAccess alloc] init];
       
        // get the array from the database
        croplistsTemp = [dbAccess getAllCropLists];
       
        // close the database finished with it
        [dbAccess closeDatabase];
       
        // release the dbAccess object to free its memory
        [dbAccess release];
       
    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem;
        UILocalizedIndexedCollation *indexedCollation = [UILocalizedIndexedCollation currentCollation];
       
        // iterate over the crops, populating their section number
        for (CropList *theCropList in croplistsTemp) {
                NSInteger section = [indexedCollation sectionForObject:theCropList collationStringSelector:@selector(name)];
                theCropList.section = section;
               
        }
       
        // get the count of the number of sections
        NSInteger sectionCount = [[indexedCollation sectionTitles] count];
       
        // create an array to hold the sub arrays
        NSMutableArray *sectionsArray = [NSMutableArray arrayWithCapacity:sectionCount];
       
        // interate over each section, creating each sub array
        for (int i=0; i<=sectionCount; i++) {
                NSMutableArray *singleSectionArray = [NSMutableArray arrayWithCapacity:1];
                [sectionsArray addObject:singleSectionArray];
        }
       
        // iterate over the crops putting each crop into the correct sub-array
        for (CropList *theCropList in croplistsTemp) {
                [(NSMutableArray *) [sectionsArray objectAtIndex:theCropList.section] addObject:theCropList];
        }
       
        // iterate over each section array to sort the items in the section
        for (NSMutableArray *singleSectionArray in sectionsArray) {
                // use the UILocalizedIndexedCollation sortedArrayFromArray: method to sort each array
                NSArray *sortedSection = [indexedCollation sortedArrayFromArray:singleSectionArray collationStringSelector:@selector(name)];
                [self.croplists addObject:sortedSection];
        }
       
        // create searchBar
        self.searchBar = [[[UISearchBar alloc] initWithFrame: CGRectMake(0.0f, 0.0f, 320.0f, 44.0f)] autorelease];
        self.tableView.tableHeaderView = self.searchBar;
       
        // create search Controller
        self.searchController = [[[UISearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self] autorelease];
        self.searchController.searchResultsDataSource  = self;
        self.searchController.searchResultsDelegate = self;
       
       
}


/*
 - (void)viewWillAppear:(BOOL)animated {
 [super viewWillAppear:animated];
 }
 */
/*
 - (void)viewDidAppear:(BOOL)animated {
 [super viewDidAppear:animated];
 }
 */
/*
 - (void)viewWillDisappear:(BOOL)animated {
 [super viewWillDisappear:animated];
 }
 */
/*
 - (void)viewDidDisappear:(BOOL)animated {
 [super viewDidDisappear:animated];
 }
 */

/*
 // Override to allow orientations other than the default portrait orientation.
 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
 // Return YES for supported orientations.
 return (interfaceOrientation == UIInterfaceOrientationPortrait);
 }
 */



#pragma mark Table view methods

// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
       
        // is the request for numberOfRowsInSection for the regular table
        if (tableView == self.tableView)
        {
                // just return the count of the crops like before
                return [self.croplists count];
        }
       
        return 1;
       
}


// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        // is the request for numberOfRowsInSection for the regular table
        if (tableView == self.tableView)
        {
               
                // just return the count of the crops like before
                return [[self.croplists objectAtIndex:section] count];
               
        }
       
        // count for the filtered table
        // first, flatten the array of arrays self.crops
        NSMutableArray *flattenedArray = [[NSMutableArray alloc] initWithCapacity:1];
        for (NSMutableArray *theArray in self.croplists)
        {
                for (int i=0; i<[theArray count]; i++)
                {
                        [flattenedArray addObject:[theArray objectAtIndex:i]];
                }
        }
       
        // setup an NSPredicate to filter the rows
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name beginswith[c]%@", self.searchBar.text];
        self.filteredCrops = [flattenedArray filteredArrayUsingPredicate:predicate];
       
        //clean up the array
        [flattenedArray release];
       
        return self.filteredCrops.count;
       
}


// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
   
    static NSString *CellIdentifier = @"Cell";
   
    CropTableViewCell *cell = (CropTableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[CropTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }
   
        // Configure the cell.
        cell.accessoryType = UITableViewCellAccessoryNone;
       
        // is the request for cellForRowAtIndexPath for the regular table?
        if (tableView == self.tableView)
        {
               
                // get the crop object
                CropList *croplist = [[self.croplists objectAtIndex:[indexPath section]] objectAtIndex:[indexPath row]];
               
               
                // set the crop to be used to draw the cell
                [cell setCropList:croplist];
               
                return cell;
        }
       
        // get the crop object
        CropList* croplist = [self.filteredCrops objectAtIndex:[indexPath row]];
       
        // set the crop to be used to draw the cell
        [cell setCropList:croplist];
       
        return cell;
}



/*
 // Override to support conditional editing of the table view.
 - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
 // Return NO if you do not want the specified item to be editable.
 return YES;
 }
 */


/*
 // Override to support editing the table view.
 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
 
 if (editingStyle == UITableViewCellEditingStyleDelete) {
 // Delete the row from the data source.
 [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
 } 
 else if (editingStyle == UITableViewCellEditingStyleInsert) {
 // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
 } 
 }
 */


/*
 // Override to support rearranging the table view.
 - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
 }
 */


/*
 // Override to support conditional rearranging of the table view.
 - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
 // Return NO if you do not want the item to be re-orderable.
 return YES;
 }
 */


#pragma mark -
#pragma mark Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
   
        // get the crop that corresponds with the cell selected
        CropList *croplist;
        if (tableView == self.tableView)
        {       
                //get the crop that corresponds iwth the touched cell
                croplist = [[self.croplists objectAtIndex:[indexPath section]] objectAtIndex:[indexPath row]];
        }
        else {
                croplist = [self.filteredCrops objectAtIndex:[indexPath row]];
               
        }
       
       
        //initialise detail view controller from the NIB xib file
        CropListDetailViewController *cropListDetailViewController = [[CropListDetailViewController alloc] initWithNibName:@"CropListDetailViewController" bundle:nil];
       
        // set titles of detail page
        [cropListDetailViewController setTitle:croplist.name];
       
        // push detail controller to the stack
        [self.navigationController pushViewController:cropListDetailViewController animated:YES];
       
        // populate the details
        [cropListDetailViewController setLabelsForCropList:croplist];
       
        // release the view controller
        [cropListDetailViewController release];
       
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
        // make sure that the section will contain some data
        if ([[self.croplists objectAtIndex:section] count] >0) {
               
                // if it does, get the section title from the UILocalizedIndexedCollation object
                return [[[UILocalizedIndexedCollation currentCollation] sectionTitles] objectAtIndex:section];
        }
        return nil;
}

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
        if (tableView == self.tableView)
        {
               
                // setup the index titles from the UILocaliszedIndexedCollation
                return [[UILocalizedIndexedCollation currentCollation] sectionIndexTitles];
        }
        return nil;
}

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex: (NSInteger)index {
        // link the sections to the labels in the table
        return [[UILocalizedIndexedCollation currentCollation] sectionForSectionIndexTitleAtIndex:index];
}



#pragma mark -
#pragma mark Memory management

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
   
    // Relinquish ownership any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
    // Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
    // For example: self.myOutlet = nil;
}


- (void)dealloc {
    [super dealloc];
}


@end



Thanks Bob for the offer of testing code.

thepianoguy April 4th, 2012 08:08 AM

Your difference is how you created your NSPredicate in the
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
method

the incorrect predicate is

Code:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name begins with[c] %@", self.searchBar.text];
and the correct one is
Code:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name beginswith[c] %@", self.searchBar.text];
There should not be a space between "begins" and "with".

Bob

Jule April 4th, 2012 08:15 PM

Thanks
 
that was it. I feel should a fool. Something so simple, but I just couldn't see it.

thanks, you are awesome.

thepianoguy April 4th, 2012 11:21 PM

The console log in the debugger actually gives a very strong indication as to where the problem was.
This is part of the log I got when I ran your code:

2012-04-04 22:59:38.141 Catalog[1005:f803] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format string "name begins with[c] %@"'
*** First throw call stack:etc

Glad you got it working.

Bob

Jule April 5th, 2012 12:15 AM

thank you again. I had used the debugger but not the debugger console, how that I know how to use that, I can find things myself. But have this forum as backup.

Just when I think I am getting confident with Xcode I learn something new. But it is fun.


All times are GMT -4. The time now is 05:43 PM.

Powered by vBulletin®
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd.
© 2013 John Wiley & Sons, Inc.