I am using search display controller in my code for searching. But it is giving some problem. When view is load search bar frame is going out of the view but whenever I am trying to search something it comes in its proper frame which I need. I am unable to recognize the problem in my code. I have attached the images which will make you more clear about the problem.
Here is the code for searching:
pragma mark UISearchDisplayController Delegate Methods
- (void)handleSearchForTerm:(NSString *)searchTerm
{
searchbar.frame = CGRectMake(391, 28, 586, 44);
[self setSavedSearchTerm:searchTerm];
if ([self searchResults] == nil)
{
NSMutableArray *array = [[NSMutableArray alloc] init];
[self setSearchResults:array];
}
[[self searchResults] removeAllObjects];
if ([[self savedSearchTerm] length] != 0)
{
int i = 0;
for (NSString *currentString in [[self contentsList]valueForKey:#"name"])
{
if ([currentString rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location != NSNotFound)
{
[[self searchResults] addObject:currentString];
[[self searchResults] addObject:[[[self contentsList]objectAtIndex:i] objectForKey:#"id"]];
[[self searchResults] addObject:[[[self contentsList]objectAtIndex:i] objectForKey:#"category"]];
NSString *searchcategory = [[[self contentsList]objectAtIndex:i] objectForKey:#"category"];
[[self searchResults] addObject:[[[self contentsList]objectAtIndex:i] objectForKey:#"flavour"]];
[[self searchResults] addObject:[[[self contentsList]objectAtIndex:i] objectForKey:#"price"]];
[[self searchResults] addObject:[[[self contentsList]objectAtIndex:i] objectForKey:#"image"]];
}
i++;
}
}
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchString:(NSString *)searchString
{
searchbar.frame = CGRectMake(391, 28, 586, 44);
[self handleSearchForTerm:searchString];
return YES;
}
- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller
{
searchbar.frame = CGRectMake(391, 28, 586, 44);
[self setSearchResults:nil];
[self setSavedSearchTerm:nil];
[[self itemstable_ipad]reloadData];
}
-(void)searchmethod
{
searchbar.frame = CGRectMake(391, 28, 586, 44);
[self setContentsList:categoryarray_ipad];
if ([self savedSearchTerm])
{
[[[self searchDisplayController] searchBar] setText:[self savedSearchTerm]];
}
}
please if anyone has idea how to set search bar frame, provide me some solution.
Thanks to all.
Thanks for viewing my problem. I have resolved this problem by using searchbar programmatically instead of search display controller.
Related
In my efforts to upgrade my application to support IOS7 I found out that ImageGallery don't load the images. in others iOS is ok.
In imageGalleryView:
- (void)initWithPhotos:(NSMutableArray *)photoURLStrings andCaptions:(NSArray *)myCaptions moveToPage:(int)page {
captions = [myCaptions copy];
photoUrls = [photoURLStrings copy];
NSLog(#"array---> %#", photoUrls);
photoLoaded = [[NSMutableArray alloc] init];
for (int i=0; i<[photoURLStrings count]; i++) {
[photoLoaded addObject:[NSNumber numberWithBool:FALSE]];
}
[pageControl setNumberOfPages:[photoUrls count]];
//scrollView= [[UIScrollView alloc] init];
scrollView.backgroundColor = [UIColor blackColor];
scrollView.pagingEnabled = TRUE;
scrollView.autoresizesSubviews = TRUE;
scrollView.contentSize = CGSizeMake(320 * [photoUrls count], scrollView.frame.size.height);
scrollView.contentOffset = CGPointMake(self.scrollView.frame.size.width*page, 0);
if (([captions objectAtIndex:page] == nil) || ([[captions objectAtIndex:page] isEqualToString:#""])) {
[textView setHidden:TRUE];
} else {
[textView setHidden:FALSE];
[textView setText:[captions objectAtIndex:page]];
}
[self showImages:page];}
- (void)showImages:(int)page {
AsyncImageViewController *asyncImageView;
if ((page>=0)&&(page<[photoUrls count])) {
if (![[photoLoaded objectAtIndex:page] boolValue]) {
[photoLoaded replaceObjectAtIndex:page withObject:[NSNumber numberWithBool:TRUE]];
asyncImageView = [[AsyncImageViewController alloc] init];
//NSLog(#"%#",[NSString stringWithFormat:#"%#",[photoUrls objectAtIndex:page]]);
[asyncImageView loadImageFromURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#",[photoUrls objectAtIndex:page]]] pos:1];
//NSLog(#"page:%i",page);
asyncImageView.frame = CGRectMake(320*page,0,320,scrollView.frame.size.height);
//[scrollView setBackgroundColor:[UIColor colorWithPatternImage:asyncImageView.image]];
[scrollView addSubview:asyncImageView];
[asyncImageView release];
}
}
page = page - 1;
if ((page>=0)&&(page<[photoUrls count])) {
if (![[photoLoaded objectAtIndex:page] boolValue]) {
[photoLoaded replaceObjectAtIndex:page withObject:[NSNumber numberWithBool:TRUE]];
asyncImageView = [[AsyncImageViewController alloc] init];
[asyncImageView loadImageFromURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#",[photoUrls objectAtIndex:page]]] pos:1];
asyncImageView.frame = CGRectMake(320*page,0,320,scrollView.frame.size.height);
[scrollView addSubview:asyncImageView];
[asyncImageView release];
}
}
page = page + 2;
if ((page>=0)&&(page<[photoUrls count])) {
if (![[photoLoaded objectAtIndex:page] boolValue]) {
[photoLoaded replaceObjectAtIndex:page withObject:[NSNumber numberWithBool:TRUE]];
asyncImageView = [[AsyncImageViewController alloc] init];
[asyncImageView loadImageFromURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#",[photoUrls objectAtIndex:page]]] pos:1];
asyncImageView.frame = CGRectMake(320*page,0,320,scrollView.frame.size.height);
[scrollView addSubview:asyncImageView];
//[scrollView setBackgroundColor:[UIColor colorWithPatternImage:asyncImageView.image]];
[asyncImageView release];}}}
In the asyncimageview:
- (void)loadImageFromURL:(NSURL*)url pos:(int) posicio {
if (connection!=nil) { [connection release]; }
if (data!=nil) { [data release]; }
NSURLRequest* request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
loading = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
if (posicio == 0) {
loading.center = CGPointMake(75/2,75/2);
}else {
loading.center = CGPointMake(160,210);
}
[loading startAnimating];
[self addSubview:loading];
[loading release];}//the URL connection calls this repeatedly as data arrives- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)incrementalData {
if (data==nil) { data = [[NSMutableData alloc] initWithCapacity:2048]; }
[data appendData:incrementalData];}//the URL connection calls this once all the data has downloaded- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection {
//so self data now has the complete image
[connection release];
connection=nil;
if ([[self subviews] count]>0) {
//then this must be another image, the old one is still in subviews
[[[self subviews] objectAtIndex:0] removeFromSuperview]; //so remove it (releases it also)
}//make an image view for the image
imageView = [[[UIImageView alloc] initWithImage:[UIImage imageWithData:data]] autorelease];
//make sizing choices based on your needs, experiment with these. maybe not all the calls below are needed.
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.autoresizingMask = ( UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight );
//[self setBackgroundColor:[UIColor colorWithPatternImage:imageView]];
[self addSubview:imageView];
imageView.frame = self.bounds;
[imageView setNeedsLayout];
[self setNeedsLayout];
[loading stopAnimating];
[data release]; //don't need this any more, its in the UIImageView now
data=nil;}
//just in case you want to get the image directly, here it is in subviews- (UIImage*) image {
UIImageView* iv = [[self subviews] objectAtIndex:0];
return [iv image];}
I checked all and saw that it is UIView instead of UIImageView. probably Apple changed something. But xCode don't throw any errors.
Any idea how to fix it?
I m running into a large problem. I have a textfield for which Im doing autocomplete feature to display a list of items when tappe inside. I display the items in tableView(autocomplete tableView). I have a UIbutton below textfield. Now when I select an item from autocomplete textfield and click on the button it is not responding.
I dont know why.
I have brought it front in didendediting and also in didSelectrow but of no use.I have added a UIbutton to ScrollView(testScroll)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
Name.text = selectedCell.textLabel.text;
[Name resignFirstResponder];
[testScroll bringSubviewToFront:btnSearch];
autocompleteTableView.hidden=true;
}
-(void)textFieldDidEndEditing:(UITextField *)textField{
if(textField==CompanyName)
{
[testScroll bringSubviewToFront:btnSearch];
}
}
Where I m going wrong ?
EDIT:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if(textField==Name)
{
autocompleteTableView.hidden = NO;
NSString *substring = [NSString stringWithString:textField.text];
substring = [substring stringByReplacingCharactersInRange:range withString:string];
[self searchAutocompleteEntriesWithSubstring:substring];
return YES;
if([Name.text length]==0)
{
autocompleteTableView.hidden = YES;
}
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
parser = [[NSXMLParser alloc] initWithData:receivedData];
[parser setDelegate:self];
[parser setShouldProcessNamespaces:NO];
[parser setShouldReportNamespacePrefixes:NO];
[parser setShouldResolveExternalEntities:NO];
[parser parse];
[parser release];
if([arr4 count]!=0)
{
self.autocompleteUrls = [[[NSMutableArray alloc] init]autorelease];
viewForautoCompleteTableView = [[UIView alloc]initWithFrame:CGRectMake(220, 370, 295, 230)];
if(autocompleteTableView)
[autocompleteTableView removeFromSuperview];
autocompleteTableView = [[UITableView alloc] initWithFrame:CGRectMake(0,0,295,150) style:UITableViewStyleGrouped];
autocompleteTableView.delegate = self;
autocompleteTableView.dataSource = self;
autocompleteTableView.scrollEnabled = YES;
autocompleteTableView.backgroundColor = [UIColor lightTextColor];
autocompleteTableView.rowHeight=28;
autocompleteTableView.backgroundView = nil;
autocompleteTableView.backgroundColor = [UIColor whiteColor];
autocompleteTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[autocompleteTableView setSeparatorColor:[UIColor orangeColor]];
[viewForautoCompleteTableView setFrame:CGRectMake(220,370 ,295,autocompleteTableView.frame.size.height)];
[viewForautoCompleteTableView addSubview:autocompleteTableView];
[self.view addSubview:viewForautoCompleteTableView];
[autocompleteUrls removeAllObjects];
for(int i=0;i<[arr4 count];i++)
{
NSString *curString = [NSString stringWithFormat:#"%# %#",[[arr4 objectAtIndex:i] valueForKey:#"Name"],[[arr4 objectAtIndex:i]valueForKey:#"LastName"]];
[autocompleteUrls addObject:curString];
}
}
[autocompleteTableView reloadData];
}
I had experienced same problem and fixed with the help of below code.
Edit below two functions as below:
in .h:
int isValueSelected;
in .m:
In viewDidLoad:
isValueSelected =0;
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (isValueSelected == 1)
{
autocompleteTableView.hidden = YES;
isValueSelected = 0;
}else{
NSString *substring = [NSString stringWithString:textField.text];
substring = [substring stringByReplacingCharactersInRange:range withString:string];
[self searchAutocompleteEntriesWithSubstring:substring];
if((substring.length ==0) || ([substring characterAtIndex:0] == 10) || (autocompleteUrls.count == 0)){
autocompleteTableView.hidden = YES;
}else{
autocompleteTableView.hidden = NO;
}
}
return YES;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
urlField.text = selectedCell.textLabel.text;
isValueSelected = 1;
autocompleteTableView.hidden = YES;
}
I have a question about adding XML to the searchbar in a tableview. I can get all the external XML file to load in the tableview, but when I hit the searchbar up top, and hit a letter, it crashes.
I think it's something really simple that I'm doing wrong. In my RootViewController, there's a function called searchTableView. I feel like that's where it's not picking up the search items. I think it's somewhere around the objectForKey:#"title". When I debug, I get this error message also: "NSCFArray objectForKey unrecognized selector". Here's my searchTableView function:
- (void) searchTableView {
NSString *searchText = searchBar.text;
NSMutableArray *searchArray = [[NSMutableArray alloc] init];
for (NSDictionary *dictionary in listOfItems)
{
NSArray *array = [dictionary objectForKey:#"title"];
[searchArray addObjectsFromArray:array];
}
for (NSString *sTemp in searchArray)
{
NSRange titleResultsRange = [sTemp rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (titleResultsRange.length > 0)
[copyListOfItems addObject:sTemp];
}
[searchArray release];
searchArray = nil;
}
Ok figured it out. For some reason this was really hard to find documentation how to do this.
Here's my RootViewController.m below.
My pList is configured as:
Root (Array)
Item0 (Dictionary)
Name (String)
Item1 (Dictionary)
Name (String)..
Here's my code, hopefully this helps anyone else looking for help on this:
#implementation RootViewController
#synthesize listOfItems, copyListOfItems;
- (void)viewDidLoad {
[super viewDidLoad];
//Initialize the array.
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"plistArray" ofType:#"plist"];
NSMutableArray* tmpArray = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
self.listOfItems = tmpArray;
[tmpArray release];
//Initialize the copy array.
copyListOfItems = [[NSMutableArray alloc] init];
//Set the title
self.navigationItem.title = #"Search";
//Add the search bar
self.tableView.tableHeaderView = searchBar;
searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
searching = NO;
letUserSelectRow = YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if (searching)
return 1;
else
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (searching)
return [copyListOfItems count];
else {
//Number of rows it should expect should be based on the section
return [listOfItems count];
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//Get the selected country
NSString *selectedCountry = nil;
if(searching)
selectedCountry = [copyListOfItems objectAtIndex:indexPath.row];
else {
// Navigation logic may go here. Create and push another view controller.
}
NSDictionary *dictionary = [self.listOfItems objectAtIndex:indexPath.row];
FoodDetail *dvController = [[FoodDetail alloc] initWithNibName:#"FoodDetail" bundle:nil andDictionary: dictionary];
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:dvController animated:YES];
[dvController release];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
// Set up the cell...
if(searching)
cell.textLabel.text = [copyListOfItems objectAtIndex:indexPath.row];
else {
cell.textLabel.text = [[self.listOfItems objectAtIndex:indexPath.row]
objectForKey:#"Name"];
}
return cell;
}
- (NSIndexPath *)tableView :(UITableView *)theTableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if(letUserSelectRow)
return indexPath;
else
return nil;
}
#pragma mark -
#pragma mark Search Bar
- (void) searchBarTextDidBeginEditing:(UISearchBar *)theSearchBar {
//This method is called again when the user clicks back from the detail view.
//So the overlay is displayed on the results, which is something we do not want to happen.
if(searching)
return;
//Add the overlay view.
if(ovController == nil)
ovController = [[OverlayViewController alloc] initWithNibName:#"OverlayView" bundle:[NSBundle mainBundle]];
CGFloat yaxis = self.navigationController.navigationBar.frame.size.height;
CGFloat width = self.view.frame.size.width;
CGFloat height = self.view.frame.size.height;
//Parameters x = origion on x-axis, y = origon on y-axis.
CGRect frame = CGRectMake(0, yaxis, width, height);
ovController.view.frame = frame;
ovController.view.backgroundColor = [UIColor grayColor];
ovController.view.alpha = 0.5;
ovController.rvController = self;
[self.tableView insertSubview:ovController.view aboveSubview:self.parentViewController.view];
searching = YES;
letUserSelectRow = NO;
self.tableView.scrollEnabled = NO;
//Add the done button.
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self action:#selector(doneSearching_Clicked:)] autorelease];
}
- (void)searchBar:(UISearchBar *)theSearchBar textDidChange:(NSString *)searchText {
//Remove all objects first.
[copyListOfItems removeAllObjects];
if([searchText length] > 0) {
[ovController.view removeFromSuperview];
searching = YES;
letUserSelectRow = YES;
self.tableView.scrollEnabled = YES;
[self searchTableView];
}
else {
[self.tableView insertSubview:ovController.view aboveSubview:self.parentViewController.view];
searching = NO;
letUserSelectRow = NO;
self.tableView.scrollEnabled = NO;
}
[self.tableView reloadData];
}
- (void) searchBarSearchButtonClicked:(UISearchBar *)theSearchBar {
[self searchTableView];
}
- (void) searchTableView {
NSString *searchText = searchBar.text;
NSMutableArray *searchArray = [[NSMutableArray alloc] init];
for (NSDictionary *dictionary in listOfItems)
{
NSString *text1 = [dictionary objectForKey:#"Name"];
[searchArray addObject:text1];
}
NSLog(#"%s: searchArray=%#", __func__, searchArray);
for (NSString *sTemp in searchArray)
{
NSRange titleResultsRange = [sTemp rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (titleResultsRange.length > 0)
[copyListOfItems addObject:sTemp];
}
[searchArray release];
searchArray = nil;
}
- (void) doneSearching_Clicked:(id)sender {
searchBar.text = #"";
[searchBar resignFirstResponder];
letUserSelectRow = YES;
searching = NO;
self.navigationItem.rightBarButtonItem = nil;
self.tableView.scrollEnabled = YES;
[ovController.view removeFromSuperview];
[ovController release];
ovController = nil;
[self.tableView reloadData];
}
- (void)dealloc {
[ovController release];
[copyListOfItems release];
[searchBar release];
[listOfItems release];
[super dealloc];
}
#end
I'm using UISearchResultsController to filter data from a fetchedResultsController. Here is the relevant code:
In RootVieweController.h:
#interface RootViewController : UITableViewController <NSFetchedResultsControllerDelegate, AdditionViewControllerDelegate, UISearchBarDelegate, UISearchDisplayDelegate> {
NSArray *filteredListContent;
NSString *savedSearchTerm;
NSInteger savedScopeButtonIndex;
BOOL searchIsActive;
}
#property (nonatomic, retain) NSArray *filteredListContent;
#property (nonatomic, copy) NSString *savedSearchTerm;
#property (nonatomic) NSInteger savedScopeButtonIndex;
#property (nonatomic) BOOL searchIsActive;
In RootViewController.m:
-(void)viewDidLoad {
[snip]
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 300, 40)];
searchBar.delegate = self;
searchBar.scopeButtonTitles = [NSArray arrayWithObjects:#"Scope 1", #"Scope 2", nil];
[searchBar sizeToFit];
searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
self.tableView.tableHeaderView = searchBar;
[searchBar release];
[self.tableView setContentOffset:CGPointMake(0, 40)];
UISearchDisplayController *searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
[self performSelector:#selector(setSearchDisplayController:) withObject:searchDisplayController];
[searchDisplayController setDelegate:self];
[searchDisplayController setSearchResultsDataSource:self];
[searchDisplayController setSearchResultsDelegate:self];
[searchDisplayController release];
self.filteredListContent = [NSMutableArray arrayWithCapacity:[[[self fetchedResultsController] fetchedObjects] count]];
if (self.savedSearchTerm) {
[self.searchDisplayController setActive:self.searchIsActive];
[self.searchDisplayController.searchBar setSelectedScopeButtonIndex:self.savedScopeButtonIndex];
[self.searchDisplayController.searchBar setText:savedSearchTerm];
self.savedSearchTerm = nil;
}
}
- (NSInteger)tableView:(UITableView *)theTableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
if (theTableView == self.searchDisplayController.searchResultsTableView) {
NSLog(#"Search Cells: %i", [self.filteredListContent count]);
return [self.filteredListContent count];
}
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
NSLog(#"Normal cells: %i", [sectionInfo numberOfObjects]);
return [sectionInfo numberOfObjects];
}
-(void)configureCell:(CustomTableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
//Called from cellForRowAtIndexPath
Object *object = nil;
if (self.searchIsActive) {
object = [[self filteredListContent] objectAtIndex:[indexPath row]];
} else {
object = [fetchedResultsController objectAtIndexPath:indexPath];
}
[snip]
}
#pragma mark -
#pragma mark Search functions
-(void)filterContentForSearchText:(NSString *)searchText scope:(NSString *)scope {
if ([scope isEqualToString:#"Scope 1"]) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"scope1 BEGINSWITH[cd] %#", searchText];
self.filteredListContent = [[[self fetchedResultsController] fetchedObjects] filteredArrayUsingPredicate:predicate];
} else {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"scope2 BEGINSWITH[cd] %#", searchText];
self.filteredListContent = [[[self fetchedResultsController]fetchedObjects] filteredArrayUsingPredicate:predicate];
}
}
#pragma mark -
#pragma mark UISearchDisplayController Delegate Methods
- (void)searchDisplayController:(UISearchDisplayController *)controller willShowSearchResultsTableView:(UITableView *)theTableView {
NSLog(#"Showing search results");
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self filterContentForSearchText:searchString scope:
[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:
[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
NSLog(#"Reloading for string");
return YES;
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
[self filterContentForSearchText:[self.searchDisplayController.searchBar text] scope:
[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:searchOption]];
NSLog(#"Reloading for scope");
return YES;
}
-(void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
self.searchDisplayController.searchResultsTableView.rowHeight = 55;
self.searchIsActive = YES;
}
-(void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller {
self.searchIsActive = NO;
}
This works great in the simulator. But on a device, it crashes on object = [[self filteredListContent] objectAtIndex:[indexPath row]]; from configureCell when trying to show the searchResultsTableView. I get the error [NSMutableArray objectAtIndex:]: index 7 beyond bounds for empty array. Always index 7. What am I missing here?
--UPDATE--
Fixed: flipped the searchIsActive BOOL to switch on searchDisplayControllerDidBeginSearch instead of searchDisplayControllerWillBeginSearch and searchDisplayControllerWillEndSearch instead of searchDisplayControllerDidEndSearch. That keeps the table from trying to configure cells that don't exist. No clue why the Simulator didn't catch this
If the array it is referencing is empty, it doesn't matter what index it is if you are trying to populate the tableview from an empty array.
Is your NSMutableArray filteredListContent populated (i.e. are you returning search results from the fetched results controller)? Have you checked the contents of the array in filterContentForSearchText:?
P.S. I like your style... BeerListTableViewCell :)
I ran into this exact same crash while working on an update to an existing app. The code is almost exactly the same as the original poster's and the only thing that changed in my app was the database. There were no code changes.
With the old database, the table view datasource methods don't get called when the search display controller starts a search.
With the new database, the table view datasource methods do get called when the search display controller starts a search.
Same Core Data entities, same database structure, same code, same nibs. Same problem in simulator or on the device.
I really can't get this to work, basically when my JSON feeds loads I want the indicator to show, then hide when it's stopped.
It loads top level menu items 1st "Publishing, Broadcasting, Marketing Services", then when Broadcasting is selected it loads a feed using the JSON framework hosted on Google. Round this load I call startIndicator and stopIndicator using the NSThread. Have I missed something?
#implementation GeneralNewsTableViewController
#synthesize dataList;
#synthesize generalNewsDetailViewController;
#synthesize atLevel;
-(void) startIndicator
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc ] init ];
[(UIActivityIndicatorView *)[self navigationItem].rightBarButtonItem.customView startAnimating];
[pool release];
}
-(void) stopIndicator
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc ] init ];
[(UIActivityIndicatorView *)[self navigationItem].rightBarButtonItem.customView stopAnimating];
[pool release];
}
- (void)viewDidLoad {
NSMutableArray *checker = self.dataList;
if(checker == nil)
{
self.title = NSLocalizedString(#"General1",#"General News");
NSMutableArray *array = [[NSArray alloc] initWithObjects:#"Publishing", #"Broadcasting",#"Marketing Services",nil];
self.dataList = [array retain];
self.atLevel = #"level1";
[array release];
}
UIActivityIndicatorView * activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
//set the initial property
[activityIndicator stopAnimating];
[activityIndicator hidesWhenStopped];
//Create an instance of Bar button item with custome view which is of activity indicator
UIBarButtonItem * barButton = [[UIBarButtonItem alloc] initWithCustomView:activityIndicator];
//Set the bar button the navigation bar
[self navigationItem].rightBarButtonItem = barButton;
//Memory clean up
[activityIndicator release];
[barButton release];
[super viewDidLoad];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *level = self.atLevel;
if([level isEqualToString:#"level2"])
{
return 70.0f;
}
else
{
return 40.0f;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *FirstLevelCell = #"FirstLevelCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:FirstLevelCell];
if(cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:FirstLevelCell] autorelease];
}
NSInteger row = [indexPath row];
NSString *level = self.atLevel;
if([level isEqualToString:#"level2"])
{
NSMutableArray *stream = [self.dataList objectAtIndex:row];
NSString *newsTitle = [stream valueForKey:#"title"];
if( ![newsTitle isKindOfClass:[NSString class]] )
{
cell.textLabel.text = #"";
}
else
{
cell.textLabel.text = [stream valueForKey:#"title"];
}
cell.textLabel.numberOfLines = 2;
cell.textLabel.font =[UIFont systemFontOfSize:10];
cell.detailTextLabel.numberOfLines = 1;
cell.detailTextLabel.font= [UIFont systemFontOfSize:8];
cell.detailTextLabel.text = [stream valueForKey:#"created"];
NSData *imageURL = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://www.website.co.uk/images/stories/img.jpg"]];
UIImage *newsImage = [[UIImage alloc] initWithData:imageURL];
cell.imageView.image = newsImage;
[imageURL release];
[newsImage release];
}
else
{
cell.textLabel.text = [dataList objectAtIndex:row];
}
return cell;
}
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
NSMutableString *levelType = (NSMutableString *) [dataList objectAtIndex:row];
if(![levelType isKindOfClass:[NSString class]])
{
if(self.generalNewsDetailViewController == nil)
{
GeneralNewsDetailViewController *generalDetail = [[GeneralNewsDetailViewController alloc] initWithNibName:#"GeneralNewsDetailView" bundle:nil];
self.generalNewsDetailViewController = generalDetail;
[generalDetail release];
}
NSDictionary *stream = [self.dataList objectAtIndex:row];
NSString *newsTitle = [stream valueForKey:#"title"];
if( ![newsTitle isKindOfClass:[NSString class]] )
{
generalNewsDetailViewController.newsTitle = #"";
}
else
{
generalNewsDetailViewController.newsTitle =[stream valueForKey:#"title"];
}
generalNewsDetailViewController.newsId = [stream valueForKey:#"id"];
generalNewsDetailViewController.fullText = [stream valueForKey:#"fulltext"];
generalNewsDetailViewController.newsImage = [stream valueForKey:#"images"];
generalNewsDetailViewController.created = [stream valueForKey:#"created"];
HowDo_v1AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
[delegate.generalNewsNavController pushViewController:self.generalNewsDetailViewController animated:YES];
}
else
{
GeneralNewsTableViewController
*generalSubDetail = [[GeneralNewsTableViewController alloc] initWithNibName:#"GeneralNewsTableView" bundle:nil];
NSMutableArray *array;
NSString *titleSelected = (NSString *) [dataList objectAtIndex:row];
if([titleSelected isEqualToString:#"Publishing"])
{
generalSubDetail.title = #"Publishing news detail";
array = [[NSArray alloc] initWithObjects:#"pub News1", #"pub News2",#"pub News3",nil];
generalSubDetail.atLevel = #"level1";
}
else if ([titleSelected isEqualToString:#"Broadcasting"])
{
generalSubDetail.title = #"Broadcasting news detail";
/// START
[self performSelectorOnMainThread:#selector(startIndicator) withObject:nil waitUntilDone:YES];
if(jSONDataAccessWrapper == nil)
{
jSONDataAccessWrapper = [JSON_DataAccess_Wrapper alloc];
}
array = [jSONDataAccessWrapper downloadJSONFeed];
[self performSelectorOnMainThread:#selector(stopIndicator) withObject:nil waitUntilDone:YES];
generalSubDetail.atLevel = #"level2";
}
else if ([titleSelected isEqualToString:#"Marketing Services"])
{
generalSubDetail.title = #"Marketing Services news detail";
array = [[NSArray alloc] initWithObjects:#"Marketing News1", #"Marketing News2",#"Marketing News3",nil];
generalSubDetail.atLevel = #"level1";
}
generalSubDetail.dataList = array;
[self.navigationController pushViewController:generalSubDetail animated:YES];
[titleSelected release];
}
}
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section
//- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSIndexPath *) section
{
return [self.dataList count];
}
Cheers for any feedback
Frames
It is usually recommended by Apple that operations on user interface should be done on the main thread.
What you can do is to defer the callback into the main thread:
- (void)startIndicator
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self performSelectorOnMainThread:#selector(startAnimating:) withObject:nil waitUntilDone:NO];
[pool release];
}
- (void)startAnimating:(id)sender
{
[(UIActivityIndicatorView *)[self navigationItem].rightBarButtonItem.customView startAnimating];
}
Check out the Thread Guide from Apple. It contains useful information.