UISearchDisplayController strange behaviour with searchResultsTableView and self.tableView - ios

this is my storyboard view and it's connections:
http://i.stack.imgur.com/uD0pT.png
http://i.stack.imgur.com/FNnVa.png
In my specific case I have the searchResultsTableView that gets its data from the first external web service and the self.tableview that fetches data from another web service.
I add some code to be clear:
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString { ... }
this fetched the first web services, in particular
return NO
and there is a:
[self.searchDisplayController.searchResultsTableView reloadData];
to reload the data when the fetch is completed.
Then we have:
-(void) doSearch:(NSString*) keyword inStore:(NSInteger) store getPage: (int) pagenum {..}
that fetches the second web service and set the results in an array called 'fetchedItems'
Now, to manage this two tables I had to write this method:
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
NSLog(#"Avvio ricerca..");
// Do the search...
NSInteger store = [self buttonSelected];
[self doSearch:searchBar.text inStore:store getPage:1];
[self.searchDisplayController setActive:NO];
}
I tried without the 'setActive:NO' but the self.searchDisplayController.searchTableView remains displayed and I can't se the "underneath" self.tableView with the 'doSearch' results
Ok. Now I have this method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"foundCell";
static NSString *suggestionCellIdentifier = #"suggestionCell";
UITableViewCell *cell;
if (tableView == self.searchDisplayController.searchResultsTableView) {
// HERE I AM WITH SEARCHDISPLAYCONTROLLER
cell = [self.tableView dequeueReusableCellWithIdentifier:suggestionCellIdentifier];
cell.textLabel.text = [self.suggestions objectAtIndex:indexPath.row];
} else {
// HERE I AM WITH SELF.TABLEVIEW
}
return cell;
}
Now it works, but there's a problem!
When i tap on the tableview with the results (denoted by self.tableview) I can't catch the tap with the method
- (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath {...}
but instead I get the re-opening of the uisearchdisplaycontroller in edit mode (so the user can tap inside the searchbar)
Where am I wrong?

fixed! When using
displaysSearchBarInNavigationBar = YES
we need that the searchbar is OUT for the tableview in the storyboard!

Related

How to create a animation for my tableviewcell images alone?

I have created expanded tableview using plist, I have populated all the values and images into my tableview. Here I want to make animation for my particular cell when user click that cell.
For example, first time images will be default, next time if I click that cell, the particular cell get expanded. Here I need to make my image has hide; again if user press it will show the image. How to do this?
Every time the user taps a cell, a UITableViewDelegate method gets called, and in this method you can reload the cell:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
When a cell is reloaded, the method below is called (between the others), and the only thing you have to do is to return a different height according with the current state of the cell:
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return (/* cell state */) ? 100.0 : 50.0;
}
You have multiple ways to store your cell's state, you can do it in its model for example.
There are other ways also, this is only a solution. But the key point is that you have to reload the cell, and return a different height according with the conditions you want to consider.
You can check my full solution in the following github
Here is some of my implementation.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
movies = [[NSArray alloc] initWithObjects:
(NSArray*)[[Section alloc ] init:#"Istanbul" movieNames:#[#"Uskudar", #"Sariyer"] isExpanded:false],
(NSArray*)[[Section alloc ] init:#"Bursa" movieNames:#[#"Osmangazi", #"Mudanya", #"Nilufer"]
isExpanded:false],
(NSArray*)[[Section alloc ] init:#"Antalya" movieNames:#[#"Alanya", #"Kas"] isExpanded:false], nil
];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return movies.count;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return ((Section*)movies[section]).movies.count ;
}
-(void)toggleSection:(ExpandableHeaderFoorterView *)headerView withSection:(int)section
{
((Section*)movies[section]).expanded = !((Section*)movies[section]).expanded;
[expandableTableView beginUpdates];
for (int i= 0; i< ((Section*)movies[section]).movies.count; i++)
{
NSArray* rowsToReload = [NSArray arrayWithObjects:[NSIndexPath indexPathForRow:i inSection:section], nil];
[expandableTableView reloadRowsAtIndexPaths:rowsToReload
withRowAnimation:UITableViewRowAnimationFade];
}
[expandableTableView endUpdates];
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
ExpandableHeaderFoorterView* headerView = [[ExpandableHeaderFoorterView alloc] initWithCustom:((Section*)movies[section]).genre withSection:(int)section withDelegate:self];
return (ExpandableHeaderFoorterView*)headerView;
}
http://www.iostute.com/2015/04/expandable-and-collapsable-tableview.html
You can see this tutorial. It's a very good tutorial based on expandable tableview cell.

Selecting different UITableViewCells from indexPath alone

I have a scenario where upon selecting a UITableViewCell in didSelectRowAtIndexPath:, I need to load and get the information from a different UITableViewCell.
I'm registering and using two different xibs to be used as my tableViewCells to allow for some more customization.
- (void)viewDidLoad{
[super viewDidLoad];
self.TABLE_ROW_HEIGHT = 66;
self.tblView.delegate = self;
self.tblView.dataSource = self;
[self.tblView registerNib:[UINib nibWithNibName:#"BasicCell" bundle:nil] forCellReuseIdentifier:#"BasicCell"];
[self.tblView registerNib:[UINib nibWithNibName:#"DetailCell" bundle:nil] forCellReuseIdentifier:#"DetailCell"];
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
//Property of the view controller which is an IndexPath
self.selectedIndex = indexPath;
BasicModel *basicModel = [self.models objectAtIndex:indexPath.row];
[self.apiClient detailModelSearch:basicModel.id];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
if([self.selectedIndex isEqual:indexPath]){
return 400.0f;
}
return 66.0f;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
BasicModel *basicModel = [self.models objectAtIndex:indexPath.row];
UITableViewCell *tableCell = nil;
if([self.selectedIndex isEqual:indexPath]){
DetailCell *detailCell = [tableView dequeueReusableCellWithIdentifier:#"DetailCell"];
tableCell = detailCell;
}
else{
BasicCell *basicCell = [tableView dequeueReusableCellWithIdentifier:#"BasicCell"];
tableCell = basicCell;
}
return tableCell;
}
-(APIClient *)apiClient{
if(!_apiClient){
_apiClient = [APIClient new];
__weak ViewController *_self = self;
_apiClient.detailModelSearchFinished = ^(DetailModel *detailModel){
_self.detailModel = detailModel;
//Problem is here
DetailCell *cell = [_self.tblView cellForRowAtIndexPath:_self.selectedIndexPath;
dispatch_async(dispatch_get_main_queue(), ^{
[_self.tblView beginUpdates];
[_self.tblView endUpdates];
[_self.tblView reloadData];
});
};
}
return _apiClient;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.models.count;
}
The basic structure is as follows.
App load and loads all BasicModels into the the models array.
User selects a cell which prompts an API detail search request
When detail search request is finished, the callback returns a DetailModel
What should happen next is since I know the selected index path of the touched cell, I want to use the DetailCell instead of the BasicCell to present the detailedInformation that comes from the DetailModel. My problem is when I call
DetailCell *cell = [_self.tblView cellForRowAtIndexPath:_self.selectedIndexPath;
I always receive the BasicCell that does not have the detailed view components I need to bind the detailModel to.
BasicCell xib
Detail Cell Xib
Table View Normal:
Table View Expanded with detail Cel xib
Ok now is very clear.
I can think of two ways, one is if you don't care about fancy animations just remove the (basic) cell and insert a new (detail) cell at the same index path, only after tho you have updated the model as well and perform the eventual type checks.
Quick and dirty, if you want something more clean you may want to refactor the model objects using polimorfism or other suitable patterns.
Another way is to update directly the cell with the received data. You may apply some fancy animations but loosing possibly some performances advantages.
Pretty simple solution actually. Reload data must be called before I can grab the expanded cell. Simple as this:
[_self.tblView beginUpdates];
[_self.tblView endUpdates];
[_self.tblView reloadData];
DetailCell *expandedCell = (DetailCell *) [_self.tblView cellForRowAtIndexPath:_self.selectedIndex];
expandedCell.lblData.text = #"IT WORKS!";
});

i am having tableviewcontroller and viewcontroller with pickerview,when i am clicking the rows in tablevc the same detail viewcontroller is opening

when i navigating one row to viewcontroller which having picker view.it is navigating there i am adding sections.when i go back to tableviewcontroller and click another row it is navigating but the section is displaying which i have added in first row.i dont want that sections in section row.can u please suggest what i have to change inorder to rectify that problem.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return self.semesteryear.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
Semester * semester=self.semesteryear[indexPath.row];
cell.textLabel.text=[NSString stringWithFormat:#"%#, %#",semester.semesterName,semester.semesterYear];
return cell;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"newsemester"]){
semesterselectionVC * newsem=[segue destinationViewController];
newsem.tableViewController=self;
}
else
{
int selectedrow =[self.tableView indexPathForSelectedRow].row;
EditSectionVC* editsectionvc=[segue destinationViewController];
editsectionvc.semester=self.semesteryear[selectedrow];
editsectionvc.semester=self.semesteryear[[self.tableView indexPathForSelectedRow].row];
editsectionvc.navigationItem.title=[NSString stringWithFormat:#"%#, %#",editsectionvc.semester.semesterName,editsectionvc.semester.semesterYear];
}
}
I think each time you are navigating and coming back your data is save in array semesteryear.Remove the contents from array when you come back to this screen.One way to do that is remove the old contents before adding the new ones from semesteryear [self.semesteryear removeAllObjects] and than add new ones want to display.

Set Text Properties of UITableViewCell object dynamically with an array - cellForRowAtIndexPath never called

I am a beginner in Objective-C & iPhone development.
I add dynamically cells in a TableView. I want to set labels's text properties with an array. I saw many tutorials, and I searched during several hours but labels are never filled.
My code is :
- (void)insertNewObject
{
for (NSInteger ic=0; ic<((pages.count)); ++ic) {
NSLog(#"%d", ic);
NSDictionary *monDico = pages[ic];
menu = [monDico objectForKey:#"Name"];
NSIndexPath *indexPathTable = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView insertRowsAtIndexPaths:#[indexPathTable] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]; // I try include & exclude : never call
}
[self.tableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = menu[indexPath.row];
NSLog(#"%#%#", #"Cell Label = ", cell.textLabel.text);
return cell;
}
Please note that insertNewObject method is called during viewDidLoad execution.
I use a breakpoint in the cellForRowAtIndexPath method : it never calls ! I try with :
explicit calling
forcing reloadData method
but did not work too.
Can you please tell me why ?
Thanks in advance.
If cellForRowAtIndexPath is not being called then most likely you have not set:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [menu count]; // indicates the number of rows in your table view
}
This method needs to return the number of rows you expect to render within your table view. The default is 0 = no rows. I'm assuming you want to show all the items in your menu array so simply return [menu count].
Check this: UITableViewDataSource Protocol Reference
If you want to access to textLabel property of your cell, then it must be style of: UITableViewCellStyleDefault. Or, if you use storyboard, then set Cell's style to Basic.
And, of course, make sure that you have set delegate and datasource properties of your tableView.
- (void)viewDidLoad
{
[super viewDidLoad];
//...
self.tableView.delegate = self;
self.tableView.dataSource = self;
}
------------------EDIT------------------
If you're using UITableViewController, then no more need to set delegate and dataSource properties manually, because they will automatically set by UITableViewController when your view did load.
If cellForRowAtIndexPath: method still not being called, then make sure that following methods that you implemented, both returns value >0:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
and
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
Set a breakpoint before return and see returning values, or just NSLog them before returning.

custom cell didSelectRowAtIndexPath not called

I created a universal master-detail application. I have a table view within a custom class (MasterViewController class). This is a UITableViewController class.
Using Storyboard, I created a custom cell in my iPhone table view. The custom cell contains 3 labels and 1 image.
In StoryBoard, this table view datasource and delegate is set to the MasterViewController class.
My custom table view cell has 'User Interaction Enabled' in the View section of the attribute inspector.
In my MasterViewController class, the UITableViewDataSource methods such as 'numberOfSectionsInTableView' are working fine.
I have a seque defined between the table view and a detailed view.
When I run the application and select a cell in the table view, the didSelectRowAtIndexPath is not called for the iPhone. My prepareForSegue method executes and the segue occurs.
I have read quite a number of posts on didSelectRowAtIndexPath not being executed, but I have not been able to solve my problem.
Any hints would be very much appreciated.
My custom cell identifier is ConversationCell. The segue identifier is ShowConversationDetails.
I debug with a breakpoint on the first line of numberOfRowsInSection and this method is never entered.
The segue works and the detail view displays my label with 'Hello' text.
Some Code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
//NSLog(#"Rows %lu",(unsigned long)[sectionInfo numberOfObjects]);
return [sectionInfo numberOfObjects];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ConversationCell";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
[[self.fetchedResultsController sections] count]);
NSManagedObject *object = [[self fetchedResultsController] objectAtIndexPath:indexPath];
self.detailViewController.detailItem = object;
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowConversationDetails"]) {
NSIndexPath *selectedIndex = [self.tableView indexPathForSelectedRow];
Event *e = nil;
e = [self.fetchedResultsController objectAtIndexPath:selectedIndex];
UIViewController *destinationViewController = [segue destinationViewController];
[segue.destinationViewController setLabel:#"Hello"];
}
}
MASTERVIEWCONTROLLER:
Here is my interface for above;
#interface MasterViewController : UITableViewController <NSFetchedResultsControllerDelegate,ASIHTTPRequestDelegate,UITableViewDelegate, UITableViewDataSource>
{
NSMutableArray *eventsArray;
}
This may be a clue to my problem. When I add the following code to prepareForSeque
NSIndexPath *selectedIndex = [self.tableView indexPathForSelectedRow];
NSManagedObject *object = [[self fetchedResultsController] objectAtIndexPath:selectedIndex];
NSString *messageTableID = [[object valueForKey:#"messagetableid"] description];
selectedIndex is empty as if a row is no longer selected when prepareForSeque is executing.
By the way, just to be safe, I removed the app from the simulator and then did a Clean on the project and nothing changed.
Tim
In addition to the checks you have already mentioned, here are a few other ones you might want to consider:
Check that the method is exactly this (no difference in letter cases) :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Check that the controller implements the UITableViewDelegate protocol
Check that interaction does work (change the selection style option so that the cell changes color on touch events)
Check that you don't have any view inside that is first responder and takes away the interaction (remove any view in the cell to test)
Try to programmatically allow selection on the table [tableView setAllowsSelection:YES];
Are you sure that your UITableViewDelegate object is correctly being set as the table view's delegate? (This is separate from setting it as the data source.)
I ended up deleting my MasterViewController and DetailViewController. I recreated them and things are now working. Not sure what I did wrong the first time. Thanks for everyone that offered advice.
Tim

Resources