UIAccessibility implementation on UITableView - uitableview

I am trying to understand how UITableView accessibility works (in order to add the support to some other libraries that work in a similar way). So I implemented UIAccessibilityContainer Protocol in MyTableView subclass of UITableView.
First of all I need to render the dataSource accessible:
- (id<UITableViewDataSource>)dataSource
{
return (id<UITableViewDataSource>)[self valueForKey:#"_dataSource"];
}
Then I reimplement:
- (NSInteger)indexOfAccessibilityElement:(id)element
{
return [[self indexPathForCell:element] row];
}
- (NSInteger)accessibilityElementCount
{
return [[self dataSource] tableView:self numberOfRowsInSection:0];
}
and accessibility still works as supposed. Last step would be to implement - (id)accessibilityElementAtIndex:(NSInteger)index:
- (id)accessibilityElementAtIndex:(NSInteger)index
{
return [[self dataSource] tableView:self cellForRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0]];
}
But apparently adding this method accessibility for the tableview stops working and I get just a VoiceOver "empty list" when navigating (with voiceover) to the tableview. Funny thing cells are returned properly and I get loads of AX ERROR: Could not find my mock parent, most likely I am stale.
I am trying to investigate, I'll post results unless someone comes up with ideas sooner.

Try to Implement those UIAccessibilityProtocal methods inside the UITableviewVell Class. Make the Cell accessible and check.

Related

TableView doesn't reload in the textViewShouldEndEditing method [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I am making an app which uses tableView having TextView as a Cell in it. And it adds more cell on click of footer of the tableView.
Now i want to reload table when textView done the editing.For that i put the [tblView reloadData] in textViewShouldEndEditing but at this time table doesn't reload.
Please help me.
You need to verify that the textView.delegate is set to an instance of the class that implements textViewShouldEndEditing. If the TextView is in a UITableViewCell subclass, then you might be setting that subclass as the delegate for the UITextView, when in fact you've implemented the delegate methods on the view controller that contains the tableView.
One approach would be this:
Put your UITextView in a UITableViewCell subclass.
Implement the UITextViewDelegate methods in your view controller that contains the UITableView. (Which may, in itself, be a UITableViewController, but it could just be a UIViewController that has a UITableView in it; either one is fine.)
Make a relationship between the cell and the containing view controller using code similar to this:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
MyCustomCellSubclass *cell = [tableView dequeueReusableCellWithIdentifier....];
cell.textView.delegate = self;
// do further cell customization if needed
return cell;
}
Then when your cell's textView finishes, it'll call back to the containing view controller.
Also, from your description, it sounds like you might prefer the delegate method:
- (void)textViewDidEndEditing:(UITextView *)textView;
instead of "shouldEndEditing", but for what you're describing, that isn't your current problem.
As an added tip, if you do [tblView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewAnimationRowAutomatic], it'll refresh the tableview using a nice little animation, instead of a hard reload like reloadData does.
First Make sure you have UITextView Delegate for the self View. Like
UITextView.delegate = self ;
After that in
- (BOOL)textFieldShouldReturn:(UITextView *)theTextField {
if (theTextField == TextView) {
[Tableview Reload];
}
return YES;
}
Try this , Let me know.
Make sure your UITextView Delegate Methods are calling by putting NSLog try with using following Delegate Method of UITextView.
-(void)textViewDidEndEditing:(UITextView *)textView {
[textView resignFirstResponder];
[self performSelector:#selector(reloadTableViewData) withObject:nil afterDelay:0.3];
}
- (void)reloadTableViewData {
[self.tableView reloadData];
}

Calling UICollectionView#reloadData in UICollectionViewDelegate#collectionView:didSelectItemAtIndexPath: hides all cells

I have a UIViewController which has the following implementation for the didSelectItemAtIndexPath
#interface
id section1Item
NSMutableArray *section2Items
NSMutableArray *section3Items
#end
#implementation
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
;
} else if (indexPath.section == 1) {
self.section1Item = [self.section2Items objectAtIndex:indexPath.row];
} else { // indexPath.section == 2
id newSection2Item = [self.section3Items objectAtIndex:indexPath.row];
[self.section2Items addObject:newSection2Item];
[self.section3Items removeObject:newSection2Item];
}
[collectionView reloadData];
}
#end
The idea behind the code is that my collectionView has a static number of sections, and taping on an item in section 3 moves the item to section 2, and tapping on an item in section 2 makes it an item in section 1.
However once I make the changes to my dataStructure (section1Item, section2Items and section3Items), and call reloadData, all my UICollectionView cells disappear. A few symptoms of the issue
After the reloadData call, non of my dataSource methods get recalled. I tried putting a breakpoint in my implementation of numberOfSectionsInCollectionView and collectionView:numberOfItemsInSection but they don't get hit.
I tried debugging using RevealApp, and I found out that after reloadData call, all my UICollectionViewCell's have their hidden property set to "YES", even though I don't have any code in my code base calling .hidden = YES;
I also tried overriding UICollectionViewCell#setHidden to detect what (if any) part of the UIKit framework calls it, and again there was no breakpoint triggers.
Tools details: I'm working with XCode5-DP6 on iOS7 simulator.
UPDATE: My UICollectionView shows all the cells correctly on first render.
Ok peeps, so I was able to figure out the issue. The delegate (self) was a subclass of UIViewController. In the init, I was assigning self.view = viewFromStoryBoard where viewFromStoryBoard was passed in by the caller and which was setup in a storyboard.
Since I was not really using any of the facilities offered by subclass UIViewController, I decided to switch to subclassing NSObject and manually retaining the pointer to the UICollectionView.
This fixed my problem. However I'm not a 100% on the exact nature of the issue. I'm guessing somehow overriding a UIViewController's view isn't all that it seems.
There are lots of bugs with iOS 7 and UICollectionView... In my case reloadData doesn't work correctly, it works with delay.

Uitableview cell changes value when scrolling

The code below is creating a search for many strings. Initially there are 5 rows, when you reach row five, it adds another row. Instead of just directly editing the row, i load a filter controller (another view controller that as you type it completes words for you). When the user finishes finding a word he clicks it and comes back to this view controller. Now i want to fill the cell that was originally tapped with the text from the filter.
I tried asking earlier and didn't get any concrete answers.
I am running into a problem where when i scroll (after adding a new row), it starts filling in those rows with info already in the table, (as opposed to staying blank)
Please help me where i am going wrong
//global indexpath to remember which cell tapped
NSIndexPath *globalPath;
#interface SearchViewController ()
#end
#implementation SearchViewController
//Load implementation once per launch
- (void)viewDidLoad
{
[super viewDidLoad];
[self linkInputTableToDelegate];
_temporaryResultsArray =[[NSMutableArray alloc]init];
_flurryArray=[[NSMutableArray alloc]init];
_numberOfSections=6;
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:NO];
[InputTable reloadData];
textFromUserDefaults=[[[HelperMethods alloc]init]getObjectUserDefault:#"textFiltered"];
[self addTextToFlurryArrayForFlurryAndSavedLists:_textFromUserDefaults];
}
-(void)viewDidDisappear:(BOOL)animated{
}
- (IBAction)searchButtonPressed:(UIButton *)sender {
self.tabBarController.selectedIndex = 1;
}
//Makes the input table respond to delegate table view methods
-(void)linkInputTableToDelegate{
_inputTable.dataSource=self;
_inputTable.delegate=self;
}
-(void)performSearch:(NSString*)text{
//do search
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
int numberOfRows=_numberOfSections;
//Rows for iPhone 4
if ([[UIScreen mainScreen]bounds].size.height==480) {
numberOfRows=numberOfRows;
//Rows for iPhone 5
}else if ([[UIScreen mainScreen]bounds].size.height==568){
numberOfRows=numberOfRows+1;
}
return numberOfRows;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//In reality groups are created with 1 row inside, this is to allow spacing between the rows
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *kCellID = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellID];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellID];
}
//Is the cell the same as the one clicked when going to ingredient filter
BOOL cellIndexPathSameAsSelected=[self isCellIndexSameAsPreviousClicked:indexPath];
cell.textLabel.textColor=[UIColor blackColor];
if (cellIndexPathSameAsSelected && _textFromUserDefaults!=nil) {
if (![cell.textLabel.text isEqualToString:_textFromUserDefaults]) {
cell.textLabel.text=_textFromUserDefaults;
[self performTextSearch:_textFromUserDefaults];
}
}
return cell;
}
//Compares the previous clicked cell with the cell now selected
-(BOOL)isCellIndexSameAsPreviousClicked: (NSIndexPath*)cellPath{
if (cellPath.row == globalPath.row && globalPath.section==cellPath.section) {
return YES;
}
else{
return NO;
}
}
- (void)updateTableViewWithExtraRow :(NSIndexPath*)rowSelected{
NSLog(#"number of sections =%i",_numberOfSections);
if (rowSelected.section == _numberOfSections) {
_numberOfSections ++;
}
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellText = [tableView cellForRowAtIndexPath:indexPath].textLabel.text;
[[[HelperMethods alloc]init]saveObjectToUserDefaults:cellText :#"textFiltered"];
globalPath = indexPath;
[self updateTableViewWithExtraRow:indexPath];
}
-(void)addTextToFlurryArrayForFlurryAndSavedLists:(NSString*)text{
if ([_flurryArray count]==0 &&[text length]>0) {
[_flurryArray addObject:text];
}
for (int i=0;i<[_flurryArray count];i++) {
NSString *textInArray=[_flurryArray objectAtIndex:i];
if (![textInArray isEqualToString:text]) {
[_flurryArray addObject:text];
}
}
NSLog(#"Total number of saved items = %i",[_flurryArray count]);
}
// Dispose of any resources that can be recreated.
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
I have a couple of reactions looking at the code:
A couple of observations about the proper use of the UITableViewDataSource methods, specifically numberOfRowsInSection, numberOfSectionsInTableView, and cellForRowAtIndexPath:
These really should be driven by some model data structure (e.g. a NSMutableArray) and nothing else;
These methods should be stateless. They should not relying on the value of some NSString instance variable, like _textFromUserDefaults) but rather always look up the value in the NSMutableArray model structure on the basis of the value of the indexPath parameter. You simply cannot make any assumptions about when cellForRowAtIndexPath will be called. This may well account for your duplicate values.
None of these should be doing anything besides responding to the UITableView inquiry. For example, your cellForRowAtIndexPath is invoking performTextSearch. It really shouldn't do anything except return the cell.
Your cellForRowAtIndexPath currently has conditional logic and only updates the cell if certain conditions holds. Because cells are reused, you really want to make sure that you initialize the cells regardless. You can't be assured that the cell is blank when you get it, nor that the previous contents are the previous values for that indexPath. Because cells are reused, it could be for an entirely different row. This could also account for your duplicative entries.
Regarding the interaction of the master view controller and the details view controller, there are more elegant ways than passing data back and forth via NSUserDefaults. For example when you initiate the details view controller, you could just pass it the information it needs. And when it's done, it should call a method in the master view controller to update the data in the master view. To do that, the master view controller should conform to some protocol of your own creation. If you see the example I shared via chat, you can see what that might look like. Anyway, by having some delegate method in the master view controller that the detail view controller calls when it's done, that eliminates the rather fragile technique of using viewDidAppear to control the updating of the master table view.
You might want to contemplate employing "edit" (which allows you to delete, possibly also edit a particular row) and "add" buttons like the standard "master-detail" template that Xcode provides. There are a number of standard conventions here that might be better than having an array of blank cells that you can then tap on. Clearly, your user experience is entirely up to you, but you can always contemplate whether there are existing, familiar conventions that you might employ.
Rob's feedback is good. In broader terms, you can't rely on the cells in a UITableView to hold onto their data. For efficiency, it will be creating, using, and destroying cells at will, and using cellForRowAtIndexPath to figure out what they should look like. Instead of testing what's in a cell, you need to have your own set of data which describe the value of each cell, and just set the value based on the indexPath. I'd recommend storing all your cell information in an NSMutableArray which contains NSStrings or something more complicated if necessary. It will be easy to set default values when you add cells to the array. Then cellForRowAtIndexPath can just access the array rather than attempting its own logic based on current cells.

UICollectionView insertItemsAtIndexPaths: throws exception

UICollectionView: I'm doing it wrong. I just don't know how.
My Setup
I'm running this on an iPhone 4S with iOS 6.0.1.
My Goal
I have a table view in which one section is devoted to images:
When the user taps the "Add Image..." cell, they are prompted to either choose an image from their photo library or take a new one with the camera. That part of the app seems to be working fine.
When the user first adds an image, the "No Images" label will be removed from the second table cell, and a UICollectionView, created programmatically, is added in its place. That part also seems to be working fine.
The collection view is supposed to display the images they have added, and it's here where I'm running into trouble. (I know that I'm going to have to jump through some hoops to get the table view cell to enlarge itself as the number of images grows. I'm not that far yet.)
When I attempt to insert an item into the collection view, it throws an exception. More on that later.
My Code
I've got the UITableViewController in charge of the table view also acting as the collection view's delegate and datasource. Here is the relevant code (I have omitted the bits of the controller that I consider unrelated to this problem, including lines in methods like -viewDidLoad. I've also omitted most of the image acquisition code since I don't think it's relevant):
#define ATImageThumbnailMaxDimension 100
#interface ATAddEditActivityViewController ()
{
UICollectionView* imageDisplayView;
NSMutableArray* imageViews;
}
#property (weak, nonatomic) IBOutlet UITableViewCell *imageDisplayCell;
#property (weak, nonatomic) IBOutlet UILabel *noImagesLabel;
#end
#implementation ATAddEditActivityViewController
- (void)viewDidLoad
{
[super viewDidLoad];
UICollectionViewFlowLayout* flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.scrollDirection = UICollectionViewScrollDirectionVertical;
imageDisplayView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 290, 120) collectionViewLayout:flowLayout]; // The frame rect still needs tweaking
imageDisplayView.delegate = self;
imageDisplayView.dataSource = self;
imageDisplayView.backgroundColor = [UIColor yellowColor]; // Just so I can see the actual extent of the view
imageDisplayView.opaque = YES;
[imageDisplayView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"Cell"];
imageViews = [NSMutableArray array];
}
#pragma mark - UIImagePickerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
/* ...code defining imageToSave omitted... */
[self addImage:imageToSave toCollectionView:imageDisplayView];
[self dismissModalViewControllerAnimated:YES];
}
#pragma mark - UICollectionViewDelegate
- (BOOL)collectionView:(UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
#pragma mark - UICollectionViewDatasource
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
[[cell contentView] addSubview:imageViews[indexPath.row]];
return cell;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [imageViews count];
}
#pragma mark - UICollectionViewDelegateFlowLayout
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return ((UIImageView*)imageViews[indexPath.item]).bounds.size;
}
#pragma mark - Image Handling
- (void)addImage:(UIImage*)image toCollectionView:(UICollectionView*)cv
{
if ([imageViews count] == 0) {
[self.noImagesLabel removeFromSuperview];
[self.imageDisplayCell.contentView addSubview:cv];
}
UIImageView* imageView = [[UIImageView alloc] initWithImage:image];
/* ...code that sets the bounds of the image view omitted... */
[imageViews addObject:imageView];
[cv insertItemsAtIndexPaths:#[[NSIndexPath indexPathForItem:[imageViews count]-1 inSection:0]]];
[cv reloadData];
}
#end
To summarize:
The collection view is instantiated and configured in the -viewDidLoad method
The UIImagePickerDelegate method that receives the chosen image calls -addImage:toCollectionView
...which creates a new image view to hold the image and adds it to the datasource array and collection view. This is the line that produces the exception.
The UICollectionView datasource methods rely on the imageViews array.
The Exception
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of items in section 0. The number of items contained in an existing section after the update (1) must be equal to the number of items contained in that section before the update (1), plus or minus the number of items inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out).'
If I'm parsing this right, what this is telling me is that the (brand new!) collection view thinks it was created with a single item. So, I added a log to -addImage:toCollectionView to test this theory:
NSLog(#"%d", [cv numberOfItemsInSection:0]);
With that line in there, the exception never gets thrown! The call to -numberOfItemsInSection: must force the collection view to consult its datasource and realize that it has no items. Or something. I'm conjecturing here. But, well, whatever: the collection view still doesn't display any items at this point, so I'm still doing something wrong and I don't know what.
In Conclusion
I get an odd exception when I attempt to add an item to a newly-minted-and-inserted collection view...except when I call -numberOfItemsInSection: before attempting insertion.
Even if I manage to get past the exception with a shady workaround, the items still do not show up in the collection view.
Sorry for the novel of a question. Any ideas?
Unfortunately the accepted answer is incorrect (although it's on the right track); the problem is that you were calling reloadData & insertItems when you should have just been inserting the item. So instead of:
[imageViews addObject:imageView];
[cv insertItemsAtIndexPaths:#[[NSIndexPath indexPathForItem:[imageViews count]-1 inSection:0]]];
[cv reloadData];
Just do:
[imageViews addObject:imageView];
[cv insertItemsAtIndexPaths:#[[NSIndexPath indexPathForItem:[imageViews count]-1 inSection:0]]];
Not only will this give you a nice animation, it prevents you from using the tableview inefficiently (not a big deal in a 1-cell collection view, but a huge problem for larger data sets), and avoids crashes like the one you were seeing, where two methods were both trying to modify the collection view (and one of them -- reloadData -- does not play well with others).
As an aside, reloadData is not very UICollectionView-friendly; if you do have a sizable &/or complex collection, and an insertion happens shortly before or after a call to reloadData, the insertion might finish before the reloadData finishes -- which will reliably cause an "invalid number of items" crash (same goes for deletions). Calling reloadSections instead of just reloadData seems to help avoid that problem.
Faced same issue but the reason with me was that I forgot to connect the collection view Data Source to view controller
It is because the [cell count] don't equal the [real index count] + [insert indexes].
Sometimes the dispatch_async don't include block of the array insert data and insertItemsAtIndexPaths.
I got the problem with somtimes crash. It is not cause each time crash.
Just a guess: at the time you are inserting the first image, the collection view may not yet have loaded its data. However, in the exception message, the collection view claims to "know" the number of items before the insertion (1). Therefore, it could have lazily loaded its data in insertItemsAtIndexPaths: and taken the result as "before" state. Also, you don't need to reload data after an insertion.
Long story short, move the
[cv reloadData];
up to get
if ([imageViews count] == 0) {
[self.noImagesLabel removeFromSuperview];
[self.imageDisplayCell.contentView addSubview:cv];
[cv reloadData];
}

Reloading UITableView behind UISearchDisplayController

I've run into this really strange phenomenon that I can't quite figure out. I have a UITableViewController that manages a UITableView. Pretty simple. I also have a UISearchDisplayController for searching the contents of the table view. The searching functionality will be able to delete items of the content displayed by the table view. So if the user chooses to delete one of the items they found while searching, I want to not only reload the UISearchDisplayController's table view but also the UITableViewController's table view. When I do that, the sections of the regular table view pop out and display above the UISearchDisplayController. It's really quite strange. I think the best way to explain it is with an image:
If any of you know what could possibly be causing this problem or know a workaround, that would be fantastic.
UPDATED AGAIN
As it turns out, if a table's header is reloaded in the background it pops in front of the search controller no matter what.
I solved this by disabling the fetchedResultsController (setting it to nil) and letting it load lazily again when needed when the search disappears.
UPDATED - Original answer below
In my case I'm using two fetchedResultsControllers one for the main tableview and one for the search.
I discovered that preventing animations when adding the section headers prevents this bug. So while searchDisplayController.active I simply disable the animation of the section change. see code below.
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
if (!self.reordering) {
UITableView *myTableView = controller == __fetchedResultsController ? self.tableView : self.searchDisplayController.searchResultsTableView;
UITableViewRowAnimation animation;
if (self.searchDisplayController.active) {
animation = UITableViewRowAnimationNone;
} else {
animation = UITableViewRowAnimationFade;
}
switch(type)
{
case NSFetchedResultsChangeInsert:
[myTableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:animation];
break;
case NSFetchedResultsChangeDelete:
[myTableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:animation];
break;
}
}
}
ORIGINAL ANSWER
The other answer doesn't actually work on it's own. The reason is, the header that is showing is not a header in the searchDisplayController's tableview. It's a header from the main tableview that for some reason is being added above the search table view in the view hierarchy.
I solved this problem by disabling updates to the main tableview while searchDisplayController.active = YES.
In my case I'm using a lazily loaded fetched results controller so I did it like this:
- (void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView {
[self.tableView reloadData];
}
- (void)searchDisplayController:(UISearchDisplayController *)controller willShowSearchResultsTableView:(UITableView *)tableView {
self.fetchedResultsController.delegate = nil;
self.fetchedResultsController = nil;
}
However, I still have the problem that if I want to reloadData on the main tableview so it is seen in the background, the section headers still float in front of the darkened area.
Does anyone have a better solution for this? It seems like a legitimate bug for viewForHeaderInSection and titleForHeaderInSection when data is reloaded while covered by a UISearchDisplayController.
The simplest answer for me is to try and override the search view so you can't see the background table. But that takes away from the "Appleness" of the app.
Our solution is to do the following. It has only been tested in iOS 7:
In viewForHeaderInSection, return nil if self.searchDisplayController.active is YES
In didHideSearchResultsTableView, call [self.tableView reloadData] to reload the headers when the search table disappears
I ran into this recently as well...the approach I decided on was to queue updates to the main tableView in a suspended serial dispatch queue until the the UISearchDisplayController hides the searchResultsTableView. I would probably consider this a bug as the section headers should not show through the main tableView if the searchResultsTableView has taken over that layer.
I solved this in iOS 7 by only reloading the visible rows in the underlying table.
- (void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView
{
[self.tableView reloadRowsAtIndexPaths:[self.tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationNone];
}
Fixed it..
Add the following lines in viewDidLoad
searchDisplayController.searchResultsTableView.delegate = self;
searchDisplayController.searchResultsTableView.dataSource = self;
That fixed it for me...
[self.searchDisplayController.searchResultsTableView reloadData];
Because of using UITableViewController. self.view is a TableView in the UITableViewController and SearchDisplayController's ContainerView is added to the self.view of UITableViewController. Just use UIViewcontroller.
My solution was to avoid reloading the table if search results were displaying, then reloading any time the search results were dismissed.
I had to set a symbolic breakpoint on UITableView reloadData to find all the calls to reload that were causing the section headers to redraw on top of the search table.
Hopefully you've figured this out by now, but just in case someone stumbles across this question: this is probably happening because your UITableViewController is the data source/delegate for the search table as well as your main table. That is, presumably, you have the same UITableViewDelegate/DataSource methods executing for both table views, and you're returning the same section header for both tables. Make sure you're handling your search results table separately:
- (NSString *)tableView:(UITableView *)aTableView titleForHeaderInSection:(NSInteger)section {
if (aTableView == [[self searchDisplayController] searchResultsTableView]) {
return nil;
}
// Return a title appropriate for self.tableView here
}

Resources