-didSelectRowAtIndexPath: not being called in UITableView - ios

When I click the UITableViewCell , It have selection effect (grey background in clicked cell),But didSelectRowAtIndexPath is not calling ,what happen?
EDIT
this is my code
tableView.h file
#interface PopCardView : MMPopupView <UITableViewDataSource, UITableViewDelegate>
#end
tableView.m file
#property (nonatomic, strong) NSMutableArray *tagsArray;
#property (nonatomic, strong) UIView *backView;
#property (nonatomic, strong) UITableView *tableView;
#property (nonatomic, assign) NSUInteger lastIndex;
#end
-(id)initWithTags:(NSMutableArray *)tags{
self = [super init];
if (self) {
self.backView = [[UIView alloc] init];
self.backView.backgroundColor = [UIColor whiteColor];
self.backView.layer.cornerRadius = 5;
self.backView.layer.masksToBounds = YES;
[self addSubview:self.backView];
[self.backView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.top.bottom.right.equalTo(self);
}];
_tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, 324, 300) style:UITableViewStylePlain];
_tableView.tableFooterView =[[UIView alloc] init];
[self.backView addSubview:_tableView];
[_tableView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.top.right.bottom.equalTo(self.backView).insets(UIEdgeInsetsMake(45,0, 45, 15));
make.size.mas_equalTo(CGSizeMake(324, 200));
}];
[_tableView registerClass:[PopCardTagViewCell class] forCellReuseIdentifier:#"cell"];
_tableView.allowsSelection = YES;
_tableView.allowsSelectionDuringEditing = YES;
[_tableView setUserInteractionEnabled:YES];
_tableView.dataSource = self;
_tableView.delegate = self;
}
return self;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[_tagsArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
PopCardData *data = (PopCardData *)obj;
data.selected = #"0";
if (idx == indexPath.row) {
data.selected = #"1";
}
}];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifer = #"cell";
PopCardTagViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:identifer];
if (!cell) {
cell = [[PopCardTagViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifer];
}
[self configureCell:cell forIndexPath:indexPath];
return cell;
}
-(void)configureCell:(PopCardTagViewCell *)cell forIndexPath:(NSIndexPath *)indexPath {
PopCardData *data = (PopCardData *)[_tagsArray objectAtIndex:indexPath.row];
//configure cell
[cell setUserInteractionEnabled:YES];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return _tagsArray.count;
}
EDIT2
this is my initialize code of PopCardView,it use swift
let pop = PopCardView(tags: self.m_model.getItmes())
pop.show()

The code you show does not set any delegate to the table view. Either this is the reason or you posted an incomplete code snippet.

self.tableView.delegate = self;
and add UITableViewDelegate to your interface like
#interface ClassName ()<UITableViewDelegate>

Make sure you don't have anything in the cell that can swallow the touch event. Things like buttons and textfields can cause this. Strip everything from your cell, test to see if it works, then add things back in slowly to find the culprit.

Related

UITableView from separate class

Case is following: I want to create UITableView from separate class.
Currently I have following:
// Menu.h
#interface Menu : UITableViewController <UITableViewDelegate, UIAlertViewDelegate> {
UITableView *tableView;
}
#property (nonatomic,retain) NSMutableArray *navigationItems;
- (void)initMenu:(UIView *)view;
#end;
Then
// Menu.m
#import <Foundation/Foundation.h>
#import "Menu.h"
#implementation Menu
- (void) initMenu:(UIView *)view {
self.navigationItems = [[NSMutableArray alloc] initWithObjects:#"One",#"Two",#"Three",#"Four",#"Five",#"Six",#"Seven",#"Eight",#"Nine",#"Ten",nil];
UIView *mainmenu=[[UIView alloc]initWithFrame:CGRectMake(0, 50, 320, 420)];
[mainmenu setBackgroundColor:[UIColor yellowColor]];
[view addSubview:mainmenu];
UITableView *menutableView = [[UITableView alloc] initWithFrame:view.bounds style:UITableViewStylePlain];
menutableView.backgroundColor = [UIColor whiteColor];
menutableView.delegate = self;
menutableView.dataSource = self;
[mainmenu addSubview:menutableView];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableViewi cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableViewi dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [self.navigationItems objectAtIndex:indexPath.row];
return cell;
}
#end
And in different .m file I call method:
...
#import "Menu.h"
...
- (void)viewDidLoad
{
[super viewDidLoad];
...
Menu *menu = [[Menu alloc] init];
[menu initMenu: self.view];
}
Running this will crash application and Xcode won't give any detailed report. However, if I combine Menu.m to the .m file where I'm calling "initMenu" it won't crash.
Also if I comment out menutableView.dataSource = self; it will run with our crash (no rows in table of course...).
Passing a view into an init method and then creating/adding subviews in said init method is an odd design pattern. Change your Menu class to a viewcontroller, then move your UIView and UITableView declarations to the viewDidLoad method. The crash is likely happening because the tableview is trying to display data before its parent view has finished loading.

How to insert a button on the bottom of every UITableView section?

I currently have a UITableView within my MatchCenterViewController, and I designed it to load up 10 rows for every section, but only show the first 4 by making the heightForRowAtIndexPath return a value of 0 for the rest. What I want to do is have a button on the bottom of every section that when pressed, will reload the data and show 10 instead of 4 for just that specific section.
I've started working on the framework for what happens when the button is pressed, I'm just having trouble with the syntax for rendering the button on the bottom and showing 10 rows for only that respective section. Here's how I have my UITableView laid out so far:
MatchCenterViewController.h:
#import <UIKit/UIKit.h>
#import <Parse/Parse.h>
#import "AsyncImageView.h"
#import "SearchViewController.h"
#import "WebViewController.h"
#import "SLExpandableTableView.h"
#interface MatchCenterViewController : UIViewController <UITableViewDataSource>
#property (strong, nonatomic) NSString *itemSearch;
#property (nonatomic, strong) NSArray *imageURLs;
#property (strong, nonatomic) NSString *matchingCategoryCondition;
#property (strong, nonatomic) NSString *matchingCategoryLocation;
#property (strong, nonatomic) NSNumber *matchingCategoryMaxPrice;
#property (strong, nonatomic) NSNumber *matchingCategoryMinPrice;
#property (strong, nonatomic) NSArray *matchCenterArray;
#property (strong, nonatomic) NSString *searchTerm;
#property (strong, nonatomic) NSString *itemURL;
#end
MatchCenterViewController.m:
#import "MatchCenterViewController.h"
#import <UIKit/UIKit.h>
#interface MatchCenterViewController () <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, strong) UITableView *matchCenter;
#property (nonatomic, assign) BOOL matchCenterDone;
#property (nonatomic, assign) BOOL hasPressedShowMoreButton;
#end
#implementation MatchCenterViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_matchCenterDone = NO;
//self.matchCenter = [[SLExpandableTableView alloc] initWithFrame:self.view.bounds style:UITableViewCellStyleSubtitle];
self.matchCenter = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewCellStyleSubtitle];
self.matchCenter.frame = CGRectMake(0,50,320,self.view.frame.size.height-100);
_matchCenter.dataSource = self;
_matchCenter.delegate = self;
[self.view addSubview:self.matchCenter];
_matchCenterArray = [[NSArray alloc] init];
}
- (void)viewDidAppear:(BOOL)animated
{
self.matchCenterArray = [[NSArray alloc] init];
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityIndicator.center = CGPointMake(self.view.frame.size.width / 2.0, self.view.frame.size.height / 2.0);
[self.view addSubview: activityIndicator];
[activityIndicator startAnimating];
_matchCenterDone = NO;
// Disable ability to scroll until table is MatchCenter table is done loading
self.matchCenter.scrollEnabled = NO;
[PFCloud callFunctionInBackground:#"MatchCenter2"
withParameters:#{}
block:^(NSArray *result, NSError *error) {
if (!error) {
_matchCenterArray = result;
[activityIndicator stopAnimating];
[_matchCenter reloadData];
_matchCenterDone = YES;
self.matchCenter.scrollEnabled = YES;
NSLog(#"Result: '%#'", result);
}
}];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return _matchCenterArray.count;
}
//the part where i setup sections and the deleting of said sections
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 21.0f;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return 0.01f;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 21)];
headerView.backgroundColor = [UIColor lightGrayColor];
_searchTerm = [[[[_matchCenterArray objectAtIndex:section] objectForKey:#"Top 3"] objectAtIndex:0]objectForKey:#"Search Term"];
UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(8, 0, 250, 21)];
headerLabel.text = [NSString stringWithFormat:#"%#", _searchTerm];
headerLabel.font = [UIFont boldSystemFontOfSize:[UIFont systemFontSize]];
headerLabel.textColor = [UIColor whiteColor];
headerLabel.backgroundColor = [UIColor lightGrayColor];
[headerView addSubview:headerLabel];
UIButton *deleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
deleteButton.tag = section;
deleteButton.frame = CGRectMake(300, 2, 17, 17);
[deleteButton setImage:[UIImage imageNamed:#"xbutton.png"] forState:UIControlStateNormal];
[deleteButton addTarget:self action:#selector(deleteButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
[headerView addSubview:deleteButton];
return headerView;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSDictionary *currentSectionDictionary = _matchCenterArray[section];
NSArray *top3ArrayForSection = currentSectionDictionary[#"Top 3"];
return top3ArrayForSection.count-1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Initialize cell
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
// if no cell could be dequeued create a new one
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// No cell separators = clean design
tableView.separatorColor = [UIColor clearColor];
// title of the item
cell.textLabel.text = _matchCenterArray[indexPath.section][#"Top 3"][indexPath.row+1][#"Title"];
cell.textLabel.font = [UIFont boldSystemFontOfSize:14];
// price of the item
cell.detailTextLabel.text = [NSString stringWithFormat:#"$%#", _matchCenterArray[indexPath.section][#"Top 3"][indexPath.row+1][#"Price"]];
cell.detailTextLabel.textColor = [UIColor colorWithRed:0/255.0f green:127/255.0f blue:31/255.0f alpha:1.0f];
// image of the item
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:_matchCenterArray[indexPath.section][#"Top 3"][indexPath.row+1][#"Image URL"]]];
[[cell imageView] setImage:[UIImage imageWithData:imageData]];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row > 3 || self.hasPressedShowMoreButton){
return 0;
}
else{
return 65;
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (_matchCenterDone == YES) {
self.itemURL = _matchCenterArray[indexPath.section][#"Top 3"][indexPath.row][#"Item URL"];
[self performSegueWithIdentifier:#"WebViewSegue" sender:self];
}
}
-(IBAction)pressedShowMoreButton{
self.hasPressedShowMoreButton = YES;
[self.matchCenter reloadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
WebViewController *controller = (WebViewController *) segue.destinationViewController;
controller.itemURL = self.itemURL;
}
#end
for this functionality you can either use special UITableviewCell or a footerView of UITableView
You can use property tableFooterView.
Below is how I use in showing load more option
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 65)];
v.backgroundColor = [UIColor clearColor];
int mySiz = 0;
// keep counter how many times load more is pressed.. initial is 0 (this is like index)
mySiz = [startNumberLabel.text intValue]+1;
// i have 15 bcz my index size is 15.
if ([feeds count]>=(15*mySiz)) {
NSLog(#"showing button...");
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setFrame:CGRectMake(10, 10, 296, 45)];
[button setBackgroundImage:[UIImage imageNamed:localize(#"loadmore")] forState:UIControlStateNormal];
[button addTarget:self action:#selector(loadMoreData:) forControlEvents:UIControlEventTouchUpInside];
[v addSubview:button];
mainTableView.tableFooterView = v;
} else {
mainTableView.tableFooterView = nil;
}
[mainTableView reloadData];
Now adjust code as per your necessity...
Ended up doing it like this:
// Create "more" button
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
view.backgroundColor = [UIColor whiteColor];
self.moreButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.moreButton.frame = CGRectMake(0, 0, 320, 44);
[self.moreButton setImage:[UIImage imageNamed:#"downarrow.png"] forState:UIControlStateNormal];
[self.moreButton addTarget:self action:#selector(moreButtonSelected:) forControlEvents:UIControlEventTouchUpInside];
[view addSubview:self.moreButton];
return view;
}
// Load rest of items
- (void)moreButtonSelected:(id)sender {
if (_hasPressedShowMoreButton == NO){
self.hasPressedShowMoreButton = YES;
}
else if (_hasPressedShowMoreButton == YES){
self.hasPressedShowMoreButton = NO;
}
[self.matchCenter reloadData];
}

iOS - [UITableView reloadData] reloads, but not removes old cells?

This is weird, I know but my [UITableView reloadData] is not removing old cells, like this:
The mess you see happened after I clicked on the + button, came back and changed values again. plus button pushes the navigationController to an another controller, and after I came back with clicking on the back button and changed the value, this is what I see. How is it possible?? I used a custom view (subclassed from UIView), which I created as a UIStepper with a UILabel. Here is the codes, the controller.m, and the .h-.m files for the custom UIView.
controller.m
#interface ViewController ()
#property NSString *docsDir;
#property sqlite3 *DB;
#property NSArray *dirPaths;
#property NSString* databasePath;
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#property BOOL isCreatedBefore;
#property NSArray *theList;
#end
#implementation ViewController
#synthesize docsDir;
#synthesize DB;
#synthesize dirPaths;
#synthesize databasePath;
- (void)viewDidLoad
{
[super viewDidLoad];
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: [NSString stringWithFormat:#"database.db"]]];
[self createDatabase];
self.theList = [self readAllEntries];
}
-(void) viewWillAppear:(BOOL)animated{
self.theList = [self readAllEntries];
[self.tableView reloadData];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.theList count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{ SeriesObject * obj = [self.theList objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellocan"];
UILabel *nameLabel = (UILabel *)[cell.contentView viewWithTag:1];
[nameLabel setText:obj.name];
CounterView *seasonCounter = [[CounterView alloc] initWithX:220 WithY:28 WithName:obj.name withCount:obj.session withCustomTag:indexPath.row];
seasonCounter.tag = 2;
CounterView *episodeCounter = [[CounterView alloc] initWithX:268 WithY:28 WithName:obj.name withCount:obj.episode withCustomTag:indexPath.row];
episodeCounter.tag = 4;
[cell.contentView addSubview:seasonCounter];
[cell.contentView addSubview:episodeCounter];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return YES if you 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) {
SeriesObject *obj = [self.theList objectAtIndex:indexPath.row];
[self deleteEntryWithID:obj.idd];
self.theList = [self readAllEntries];
[self.tableView reloadData];
}
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 88;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
______and more about reading from database or deleting; not about the view. (this is a very simple app, as a free time hobby; so I didn't spend time to follow MVC)
CounterView.h
#interface CounterView : UIView
#property NSString* name;
#property NSInteger count;
#property UILabel *label;
#property NSInteger customTag;
- (id)initWithX:(CGFloat)xPoint WithY:(CGFloat)yPoint WithName:(NSString*)newName withCount:(NSInteger)newCount withCustomTag:(NSInteger)newTag;
#end
CounterView.m
#interface CounterView()
#property NSString *docsDir;
#property sqlite3 *DB;
#property NSArray *dirPaths;
#property NSString* databasePath;
#end
#implementation CounterView
#synthesize docsDir;
#synthesize DB;
#synthesize dirPaths;
#synthesize databasePath;
- (id)initWithX:(CGFloat)xPoint WithY:(CGFloat)yPoint WithName:(NSString*)newName withCount:(NSInteger)newCount withCustomTag:(NSInteger)newTag
{
self = [super initWithFrame:CGRectMake(xPoint, yPoint, 24, 52)];
if (self) {
self.customTag = newTag;
self.count = newCount;
self.name = newName;
UIButton *btnUp = [[UIButton alloc] initWithFrame:CGRectMake(3, 2, 18, 12)];
[btnUp setImage:[UIImage imageNamed:#"top.png"] forState:UIControlStateNormal];
[btnUp addTarget:self action:#selector(increaseValue) forControlEvents:UIControlEventTouchUpInside];
UIButton *btnDown = [[UIButton alloc] initWithFrame:CGRectMake(3, 38, 18, 12)];
[btnDown setImage:[UIImage imageNamed:#"bottom.png"] forState:UIControlStateNormal];
[btnDown addTarget:self action:#selector(decreaseValue) forControlEvents:UIControlEventTouchUpInside];
self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 14, 24, 24)];
[self.label setText:[NSString stringWithFormat:#"%ld", (long)self.count]];
self.label.textAlignment = NSTextAlignmentCenter;
[self addSubview:btnUp];
[self addSubview:btnDown];
[self addSubview:self.label];
}
return self;
}
- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents{
}
-(void) increaseValue{
self.count++;
[self.label setText:[NSString stringWithFormat:#"%ld", (long)self.count]];
}
-(void) decreaseValue{
self.count--;
[self.label setText:[NSString stringWithFormat:#"%ld", (long)self.count]];
}
____and some more database codes too..
In your cellForRowAtIndexPath: you are adding a subview every time. Cells are reused by UITableView, so when you reload you're getting a "dirty" cell. You need to check if the view is already there. If so, modify the view instead of adding one. Google "UITableViewCell viewWithTag" to see some sample code.
- (void)prepareForReuse
{
//remove your subviews here
[self.subViewToRemove removeFromSuperView];
}
I would recommend that you create a custom cell class derived from UITableViewCell and have it include your custom CounterView instances. In this case you won't need to add the subviews each time in your cellForRowAtIndexPath (Which is causing the problem you're having), you can instead pass it whatever values it requires.
after some modifications, using this in the cellForRowAtIndexpath: method solved everything. Thanks everyone.
if (cell != nil)
{
NSArray* subviews = [cell.contentView subviews];
for (UIView* view in subviews)
{
[view removeFromSuperview];
}
}

UISearchDisplayController delegate methods not being called

I am trying to gain some knowledge on UISearchDisplayController and going through some tutorial with examples, I have the below class ready with a search bar and table view with data on it.
Header file:
#import <UIKit/UIKit.h>
#interface MyClass : UIViewController <UITableViewDataSource, UITableViewDelegate, UISearchDisplayDelegate, UISearchBarDelegate>
#property (nonatomic, strong) IBOutlet UITableView *suggestionsTableView;
#property (nonatomic, strong) IBOutlet UISearchBar *searchBar;
#end
Implementation file:
#import "MyClass.h"
#interface DVWNoteTypeSuggestionDisplayController ()
#property (nonatomic, strong) NSArray *items;
#property (nonatomic)BOOL isSearching;
#property (nonatomic, strong) NSMutableArray *filteredList;
#end
#implementation MyClass
- (id)init
{
self = [super initWithNibName:#"SuggestionDisplayController" bundle:BUNDLE];
if (self)
{
// Set the title.
self.title = #"test";
}
return self;
}
- (void)viewDidLoad
{
self.searchBar = [[UISearchBar alloc] init];
[[UISearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self];
self.searchDisplayController.searchResultsDelegate = self;
self.searchDisplayController.searchResultsDataSource = self;
self.searchDisplayController.delegate = self;
self.searchBar.frame = CGRectMake(0, 0, 0, 38);
self.suggestionsTableView.tableHeaderView = self.searchBar;
self.items = [[NSArray alloc] initWithObjects:#"Item No. 1", #"Item No. 2", #"Item No. 3", #"Item No. 4", #"Item No. 5", #"Item No. 6", nil];
self.isSearching = NO;
self.filteredList = [[NSMutableArray alloc] init];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
//- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
// // Return the number of rows in the section.
// // Usually the number of items in your array (the one that holds your list)
// return [self.items count];
//}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
if (self.isSearching)
{
//If the user is searching, use the list in our filteredList array.
return [self.filteredList count];
} else
{
return [self.items count];
}
}
//- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// //Where we configure the cell in each row
//
// static NSString *CellIdentifier = #"Cell";
// UITableViewCell *cell;
//
// cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// if (cell == nil) {
// cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// }
// // Configure the cell... setting the text of our cell's label
// cell.textLabel.text = [self.items objectAtIndex:indexPath.row];
// return cell;
//}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// Configure the cell...
NSString *title;
if (self.isSearching && [self.filteredList count]) {
//If the user is searching, use the list in our filteredList array.
title = [self.filteredList objectAtIndex:indexPath.row];
} else
{
title = [self.items objectAtIndex:indexPath.row];
}
cell.textLabel.text = title;
return cell;
}
- (void)filterListForSearchText:(NSString *)searchText
{
[self.filteredList removeAllObjects]; //clears the array from all the string objects it might contain from the previous searches
for (NSString *title in self.items) {
NSRange nameRange = [title rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (nameRange.location != NSNotFound) {
[self.filteredList addObject:title];
}
}
}
#pragma mark - UISearchDisplayControllerDelegate
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
//When the user taps the search bar, this means that the controller will begin searching.
self.isSearching = YES;
}
- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller {
//When the user taps the Cancel Button, or anywhere aside from the view.
self.isSearching = NO;
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterListForSearchText:searchString]; // The method we made in step 7
// Return YES to cause the search result table view to be reloaded.
return YES;
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption
{
[self filterListForSearchText:[self.searchDisplayController.searchBar text]]; // The method we made in step 7
// Return YES to cause the search result table view to be reloaded.
return YES;
}
#end
Whenever I try to search for any items in the data set (eg: "Item No. 5") its not hitting the breakpoints on any of the delegate i.e. actually the search is not working. Please suggest what am I missing here as this is just my learning project right now.
It appears that a UISearchDisplayController created programatically in this way is prematurely zeroing the delegate, even though the view controller is retaining the UISearchDisplayController as expected.
Add the following to the end of your viewDidLoad and you'll see that the first log will be a valid object, but the second will be null.
NSLog(#"Delegate should be %#", self.searchDisplayController.delegate);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(#"Delegate is %#", self.searchDisplayController.delegate);
});
The quickest way I've found to get around this is to store your own reference to the UISearchDisplayController via a private property or ivar.
If you have to create object for search bar controller and set delegate search bar its work.
UISearchBar *searchBar = [[UISearchBar alloc] init];
[[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
self.searchDisplayController.searchResultsDelegate = self;
self.searchDisplayController.searchResultsDataSource = self;
self.searchDisplayController.delegate = self;
searchBar.frame = CGRectMake(0, 0, 0, 38);
self.tableView.tableHeaderView = searchBar;

tableview:cellForRowAtIndexPath never called

I'm very confusing with this.
I'm trying to create an UITableView grouped programmatically, using the single view template from Xcode. Looking at internet for some examples, there is no secret, the approach to do this is very simple. I'm not sure if my implementation are wrong or right, because the method tableView:cellForRowAtIndexPath: is never called, but the other ones are called and return a integer > 0.
There is code, any suggestions are welcome.
Thanks,
#import "ViewController.h"
#import "SimpleCell.h"
#interface ViewController () <UITableViewDelegate, UITableViewDataSource>
#property (nonatomic, strong) UITableView *table;
#property (nonatomic, strong) NSArray *sections;
#property (nonatomic, strong) NSArray *section1;
#property (nonatomic, strong) NSArray *section2;
#property (nonatomic, strong) NSArray *section3;
#end
#implementation ViewController
static NSString * const CellIdentfier = #"Cell";
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.view addSubview:self.table];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[table]|"
options:0
metrics:nil
views:#{#"table": self.table}]];
dispatch_async(dispatch_get_main_queue(), ^{
[self.table reloadData];
});
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (UITableView *)table
{
if(!_table)
{
_table = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
_table.delegate = self;
_table.dataSource = self;
_table.translatesAutoresizingMaskIntoConstraints = NO;
_table.rowHeight = 34.0f;
_table.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
_table.backgroundColor = [UIColor grayColor];
_table.showsVerticalScrollIndicator = NO;
[_table registerClass:[SimpleCell class] forCellReuseIdentifier:CellIdentfier];
}
return _table;
}
- (NSArray *)sections
{
if(!_sections)
{
_sections = #[#"Section1", #"Section2", #"Section3"];
}
return _sections;
}
- (NSArray *)section1
{
if(!_section1)
{
_section1 = #[#"Player a", #"Player b", #"Player c"];
}
return _section1;
}
- (NSArray *)section2
{
if(!_section2)
{
_section2 = #[#"Zone a", #"Zone b", #"Zone c"];
}
return _section2;
}
- (NSArray *)section3
{
if(!_section3)
{
_section3 = #[#"Area a", #"Area b", #"Area c"];
}
return _section3;
}
#pragma mark - UI Table View Delegate impl
#pragma mark - UI Table View Datasource impl
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
DLog();
SimpleCell *cell = [self.table dequeueReusableCellWithIdentifier:CellIdentfier];
if(!cell)
cell = [[SimpleCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentfier];
cell.label.text = [NSString stringWithFormat:#"Section: %i Row: %i", indexPath.section, indexPath.row];
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger total = 0;
if(section == 0) total = self.section1.count;
if(section == 1) total = self.section2.count;
if(section == 2) total = self.section3.count;
DLog(#"Rows: %i", total);
return total;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
DLog();
return self.sections.count;
}
#end
Delete this:
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[table]|"
options:0
metrics:nil
views:#{#"table": self.table}]];
It should be called then.
EDIT:
Change this as well:
_table = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStyleGrouped];
This seems to fix it but I'm not sure why. I'm guessing that it has something to do with the table frame having to be larger than 0.

Resources