I have a TableView with many rows, most are not visible at the time of loading viewController. The rows of UITableView are extracted from a SQLite database. How can I make do that the SearchBar search between all rows and not just the visible ones?
In header file:
#interface ExhibitorsViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate>{
BOOL isSearchOn;
BOOL canSelectRow;
NSMutableArray * listOfExpositors;
NSMutableArray * searchResult;
}
//....
#end
In implementation file
-(NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
if(isSearchOn){
return [searchResult count];
//In this array there are the elements after use of searchBar
}else{
int number=[self.mutableArray count];
//In this array there are all elements of database, extracts in viewDidLoad()
return number;
}
}
- (UITableViewCell *)tableView:(UITableView *)aTableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] ;
}
if(isSearchOn){
NSString * cellValue = [searchResult objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
}else{
//loading data from the database
Database *currow =[self.mutableArray objectAtIndex:indexPath.row];
cell.textLabel.text = currow.name;
[listOfExpositors addObject:cell.textLabel.text];
//here only loads the list of names visible and not the entire table
//How do I put all the elements in this array?
NSLog(#" %#", listOfExpositors);
isSearchOn = NO;
canSelectRow = YES;
}
}
-(void) doneSearching{
isSearchOn = NO;
canSelectRow = YES;
self.tableView.scrollEnabled = YES;
[self.searchBar resignFirstResponder];
[self.tableView reloadData];
}
-(void) searchBarTextDidBeginEditing:(UISearchBar *)searchBar{
isSearchOn = YES;
if(self.searchBar.text.length>0){
canSelectRow=YES;
self.tableView.scrollEnabled = YES;
}else{
canSelectRow= NO;
self.tableView.scrollEnabled = NO;
}
}
-(void) searchExpositorsTableView{
[searchResult removeAllObjects];
for (NSString *str in listOfExpositors){
NSRange titleResultsRange = [str rangeOfString:self.searchBar.text options:
NSCaseInsensitiveSearch];;
if (titleResultsRange.length >0) {
[searchResult addObject:str];
}
}
NSLog(#"%#", searchResult);
}
-(void) searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
if([searchText length]>0){
canSelectRow = YES;
self.tableView.scrollEnabled = YES;
[self searchExpositorsTableView];
}else{
canSelectRow = NO;
self.tableView.scrollEnabled = NO;
}
[self.tableView reloadData];
}
-(void) searchBarSearchButtonClicked:(UISearchBar *)searchBar{
[self searchExpositorsTableView];
[self.searchBar resignFirstResponder];
}
-(NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if(canSelectRow){
return indexPath;
}else{
return nil;
}
NSLog(#"%d", indexPath.row);
}
It was wrong to use the array created in cellForRowAtIndexPath because it was limited only to the visible elements. I then used the NSMutableArray created in viewDidLoad () that does contain all the elements of the database. I changed the following methods:
- (UITableViewCell *)tableView:(UITableView *)aTableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//....
if(isSearchOn){
NSString * cellValue = [searchResult objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
}else{
Database *currow =[self.mutableArray objectAtIndex:indexPath.row];
cell.textLabel.text = currow.name;
//Should be removed this array and used to another, self.mutableArray
//[listOfExpositors addObject:cell.textLabel.text];
// NSLog(#" %#", listOfExpositors);
isSearchOn = NO;
canSelectRow = YES;
}
}
Method for research
-(void) searchExpositorsTableView{
[searchResult removeAllObjects];
for (Database *currow in self.mutableArray){
/*In self.mutableArray there are all elements because is created in
viewDidLoad*/
NSLog(#"list of expositors %#", self.mutableArray);
NSRange titleResultsRange = [currow.name rangeOfString:self.searchBar.text options: NSCaseInsensitiveSearch];
if (titleResultsRange.length >0) {
[searchResult addObject:currow.name];
}
}
NSLog(#"%#", searchResult);
}
Related
I have one tableview and I created one UISearchController programmatically and added to tableview.
Initially it looks good but when I press on inside the search bar it looks below.
I don't want to keep my searchbar in navigation bar. And I can not use UITableViewController.
Find the code below which I implemented.
My .h file
#property (strong, nonatomic) UISearchController *searchController;
NSMutableArray *tableData;
NSArray *filteredContentList;
My .m file
// New SearchController.
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.searchBar.delegate = self;
self.searchController.searchBar.searchBarStyle = UISearchBarStyleProminent;
[self.searchController.searchBar sizeToFit];
self.tblUserList.tableHeaderView = self.searchController.searchBar;
self.definesPresentationContext = YES;
#pragma mark - UISearchDisplayDelegate
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController {
NSString *searchString = searchController.searchBar.text;
NSPredicate *resultPredicate;
//resultPredicate = [NSPredicate predicateWithFormat:#"displayname contains[c] %#",searchString];
resultPredicate = [NSPredicate predicateWithFormat:#"value contains[c] %#", searchString];
filteredContentList = [tableData filteredArrayUsingPredicate:resultPredicate];
//filteredContentList = [[tableData valueForKey:#"data"] filteredArrayUsingPredicate:resultPredicate];
[self.tblUserList reloadData];
}
- (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope {
[self updateSearchResultsForSearchController:self.searchController];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
CGRect searchBarFrame = self.searchController.searchBar.frame;
[self.tblUserList scrollRectToVisible:searchBarFrame animated:NO];
return NSNotFound;
}
I want to show my searchbar above the tableview not in naviationbar.
Thanks in advance.
Late answer by myself.
I use UITextFiled instead of UISearchBar. Below is my code implementation.
[self.searchTextField addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
And my textFieldDidChange method
-(void)textFieldDidChange:(UITextField *)textField
{
searchTextString=textField.text;
[self updateSearchArray:searchTextString];
}
-(void)updateSearchArray:(NSString *)searchText {
if(searchText.length==0) {
isFilter=NO;
} else {
isFilter=YES;
filteredContentList = [[NSMutableArray alloc]init];
NSPredicate *resultPredicate;
resultPredicate = [NSPredicate predicateWithFormat:#"value contains[c] %#", searchText];
filteredContentList = [tableData filteredArrayUsingPredicate:resultPredicate];
[self.tblUserList reloadData];
}
}
And my TableView methods:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSInteger numOfSections = 0;
if ([filteredContentList count] || [tableData count]) {
_tblUserList.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
numOfSections = 1;
_tblUserList.backgroundView = nil;
} else {
UILabel *noDataLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, _tblUserList.bounds.size.width, _tblUserList.bounds.size.height)];
noDataLabel.text = NSLocalizedString(#"No Users found", #"Message");
noDataLabel.textColor = [UIColor blackColor];
noDataLabel.textAlignment = NSTextAlignmentCenter;
_tblUserList.backgroundView = noDataLabel;
_tblUserList.separatorStyle = UITableViewCellSeparatorStyleNone;
}
return numOfSections;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
/*if (isSearching) {
return [filteredContentList count];
}
else {
return [tableData count];
}*/
if (isFilter) {
return [filteredContentList count];
} else {
return [tableData count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = #"SimpleTableItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
//cell.textLabel.text = [[tableData objectAtIndex:indexPath.row] valueForKeyPath:#"data.displayname"];
// Configure the cell...
if (isFilter) {
//cell.textLabel.text = [filteredContentList objectAtIndex:indexPath.row];
cell.textLabel.text = [[filteredContentList objectAtIndex:indexPath.row] valueForKeyPath:#"data.displayname"];
}
else {
cell.textLabel.text = [[tableData objectAtIndex:indexPath.row] valueForKeyPath:#"data.displayname"];
}
return cell;
}
I'm stumped. For some reason, when I tap my tableView cell, didSelectRowAtIndexPath is not executing? And yes, my tableView delegate is set, and data is populated in the cell label. Am I missing something obvious from my below? Essentially, when my user taps the tableView cell, the contents of the cell label should appear in a textfield.
.h
#interface RegisterViewController : UIViewController <UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource, UIImagePickerControllerDelegate> {
}
#property (nonatomic) IBOutlet UITableView *tableView;
#end
.m
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.hidden = NO;
self.tableView.delegate = self;
self.tableView.dataSource = self;
}
- (void)LoadJson_search{
searchArray=[[NSMutableArray alloc]init];
// NSLog(#"str......%#",strSearch);
// This API key is from https://developers.google.com/maps/web/
NSString *str1 = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/queryautocomplete/json?input=%#&key=AIzaSyAm7buitimhMgE1dKV2j4_7doULluiiDzU", strSearch];
NSURL *url = [NSURL URLWithString:str1];
NSData *data = [NSData dataWithContentsOfURL:url];
NSError *error=nil;
if(data.length==0)
{
}
else
{
NSDictionary *jsondic= [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
// NSLog(#"1,,,,%#",jsondic);
[searchArray removeAllObjects];
if([[jsondic objectForKey:#"status"]isEqualToString:#"ZERO_RESULTS"])
{
}
else if([[jsondic objectForKey:#"status"]isEqualToString:#"INVALID_REQUEST"])
{
}
else
{
for(int i=0;i<[jsondic.allKeys count];i++)
{
NSString *str1=[[[jsondic objectForKey:#"predictions"] objectAtIndex:i] objectForKey:#"description"];
[searchArray addObject:str1];
}
self.tableView.hidden = NO;
// NSLog(#"%#", searchArray);
}
if (searchArray.count == 0) {
self.tableView.hidden = YES;
}else{
[self.tableView reloadData];
}
}
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
// if (self.addressField.tag == 3) {
if (textField == self.addressField) {
strSearch = [self.addressField.text stringByReplacingCharactersInRange:range withString:string];
if([string isEqualToString:#" "]){
}else{
[self LoadJson_search];
}}
// }
return YES;
}
- (BOOL)textFieldShouldClear:(UITextField *)textField{
self.tableView.hidden = YES;
[self.tableView reloadData];
return YES;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return searchArray.count;
}
-(UITableViewCell *)tableView:(UITableView*)aTableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"cell"];
if(!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
cell.textLabel.text = [searchArray objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"TAPPED CELL");
self.addressField.text = [searchArray objectAtIndex:indexPath.row];
self.tableView.hidden = YES;
[self.tableView reloadData];
}
Try with the next line in your viewDidLoad:
self.tableView.allowsSelection = YES;
Or check that property in your storyboard. Well you can try with the cell too like this:
// This line do not affect the selection delegate only the style
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.userInteractionEnabled = YES;
I'm having a weird issue on UITableView delete action since iOS 11.
Here's the relevant TableView code :
#implementation ChatMessageListViewController(TableView)
#pragma mark - table view datasource/delegate
- (NSArray<UITableViewRowAction *> *) tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(nonnull NSIndexPath *)indexPath{
NSMutableArray *rowActions = [NSMutableArray array];
UITableViewRowAction *delete = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:#"Delete" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
[self deleteMessageAtIndexPath:indexPath];
}];
delete.backgroundColor = [UIColor redColor];
[rowActions addObject:delete];
return [rowActions copy];
}
- (void) deleteMessageAtIndexPath:(NSIndexPath *)indexPath {
NSString *threadID = [[self.messageArray objectAtIndex:indexPath.row] objectForKey:#"threadID"];
[self.tableView beginUpdates];
[self.messageArray removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
#weakify(self);
[UIUtil showLoadingHudWithText:WELocalString(#"message_remove_thread_loading_text", #"Deleting...", #"删除中...")];
[[AsyncUtil sharedInstance] dispatch_background_network:^{
DBManager *db = [[DBManager alloc] init];
[db deletetableData:[NSString stringWithFormat:#"singleChat WHERE threadID = '%#' ",threadID] ];
[[MemChatThreadMessages sharedInstance] removeThread:threadID];
NSDictionary * result = [Network deleteChatThread:threadID forEmail:[WEUtil getEmail]];
[[AsyncUtil sharedInstance] dispatch_main:^{
[UIUtil hideLoadingHuds];
#strongify(self);
if(self == nil) return ;
if([result[#"result"] isEqualToString:#"success"]){
}else{
[UIUtil showErrorMessage:WELocalString(#"message_remove_thread_error", #"Cannot delete this thread", #"不能删除该会话!")];
}
[self.tableView reloadData];
}];
}];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [self.messageArray count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
NSDictionary *messageInfo = [self.messageArray objectAtIndex:indexPath.row];
if ([(NSString *)[messageInfo objectForKey:#"isAnnouncement"] isEqualToString:#"1"]) {
return 80;
}else if ([[messageInfo objectForKey:#"chatTag"] isValidString]){
return 80;
}else if([self isSpecialMessage:messageInfo]){
return 80;
}else{
return 67;
}
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"message";
if(self.events == nil){
NSDictionary * d = [WEUtil getMyEventListCache];
self.events = [[NSMutableDictionary alloc] init];
for(NSDictionary * eventSummary in d[#"events"]){
NSString * eventID = eventSummary[#"eventid"];
[self.events setObject:eventSummary forKey:eventID];
}
}
UserMessageTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil){
cell = [[UserMessageTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
if(indexPath.row >= [self.messageArray count]){
TERMINATE_WITH_NIL_CELL;
}
NSDictionary *messageInfo = [self.messageArray objectAtIndex:indexPath.row];
if(![self isSpecialMessage:messageInfo]){
[cell configureCellWithMessageDict:messageInfo];
}else{
[cell configureCellWithNewMessageDict:messageInfo withEvents:self.events];
}
return cell;
}
#pragma mark - Navigation
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSDictionary *msgThreadDict = [self.messageArray objectAtIndex:indexPath.row];
if(![self isSpecialMessage:msgThreadDict]){
[self tableView:tableView didSelectNormalRowAtIndexPath:indexPath];
}else{
NSString * event = msgThreadDict[#"event"];
if([event isValidString]){
if([event isEqualToString:#"no_event_messages"]){
[UIUtil showErrorMessage:#"no event id"];
}else{
[BackendTracking trackingWithAction:#"open_special" withLabel:#"threads_list"];
SpecialTopicListViewController * special = [[SpecialTopicListViewController alloc] init];
special.tracking_src = #"tab";
[self.navigationController pushViewController:special animated:YES];
}
}
}
}
-(void) tableView:(UITableView *)tableView didSelectNormalRowAtIndexPath:(NSIndexPath *)indexPath{
NSDictionary *msgThreadDict = [self.messageArray objectAtIndex:indexPath.row];
NSString *threadID = [msgThreadDict objectForKey:#"threadID"];
NSString *jid = [msgThreadDict objectForKey:#"jid"];
[GATracking trackCategory:#"message" withAction:#"thread_list_item_click" withLabel:threadID];
[[MemChatThreadMessages sharedInstance] setCurrentThreadID:threadID];
PrivateMessageViewController * chatVC = [[PrivateMessageViewController alloc] init];
chatVC.threadID = threadID;
chatVC.targetJID = jid;
chatVC.targetName = [msgThreadDict objectForKey:#"name"];
chatVC.unreadMsgNumber = [[self.messageArray objectAtIndex:indexPath.row][#"unreadCnt"] integerValue];
if ([(NSString *)[msgThreadDict objectForKey:#"isGroup"] isEqualToString:#"1"]) {
chatVC.isGroup = YES;
}else{
chatVC.isGroup = NO;
}
chatVC.src = #"list";
WELogInfo(#"click message");
[self.navigationController pushViewController:chatVC animated:YES];
}
#end
With the update and the changes using those trailing swipe actions there is another View appended before each time I delete an entry (until it doesn't work anymore). I've tried disabling the full trail or implementing iOS 11 trailingSwipeActionsConfigurationForRowAtIndexPath but I can't resolve this issue so far.
Do you see something wrong in the code? The main controller code is in another file.
Try reloading after you delete, after this line
[self.tableView endUpdates];
I think you removed the data from messageArray but as you are not reloading just after that so table view count is still 2 and you are reloading inside the block which might be taking time.
And one more thing you already removing data from messageArray, and then removing from db, So if you fail to remove it from db you are showing its not removed but for user it will be removed, as its no longer in message array
Hi in my array there is huge amount of data and I have to display it in UITableView. But the condition here is I have to display only 5 records initially,then once the user scroll down I have to load more records.I tried searching it but didn't get any useful answer please help me and I agree that we have to use ((void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath )
Another way
we can adjust the return value of tableView:numberOfRowsInSection: method, every time we want to insert ten rows, you can plus 5 to the return value.
but i am not understand how to do this please help me
my code:
#import "TableViewController.h"
#interface TableViewController ()
{
UITableView * tableView;
NSUInteger reloads_;
NSMutableArray * MainArray;
int scrollValue;
long dataLimit;
NSArray * yourDataSource;
}
#end
#implementation TableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
MainArray = [[NSMutableArray alloc]initWithObjects:#"1",#"2",#"3",#"4",#"5",#"6",#"7",#"8",#"9",#"10",nil];
tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
tableView.delegate = self;
tableView.dataSource = self;
tableView.backgroundColor = [UIColor clearColor];
[self.view addSubview:tableView];
}
#pragma mark - UITableViewDataSource
// number of section(s), now I assume there is only 1 section
- (NSInteger)numberOfSectionsInTableView:(UITableView *)theTableView
{
return 1;
}
// number of row in the section, I assume there is only 1 row
- (NSInteger)tableView:(UITableView *)theTableView numberOfRowsInSection:(NSInteger)section
{
return yourDataSource.count;
}
// the cell will be returned to the tableView
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"newFriendCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [yourDataSource objectAtIndex:indexPath.row];
return cell;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
[self estimatedTotalData];
}
- (void)estimatedTotalData
{
long currentRow = ((NSIndexPath *)[[tableView indexPathsForVisibleRows] lastObject]).row;
// 25 here is the initial data count
long estimateDataCount = 25;
while (currentRow > estimateDataCount)
{
estimateDataCount+=25;
}
dataLimit = estimateDataCount;
if (dataLimit == currentRow+1)
{
dataLimit+=25;
if (dataLimit != estimateDataCount)
{
//[self requestForData]; or load necessary data
// take not that dataLimit is the total data that must be displayed.
NSArray *yourLocalData = #[#"1", #"2", #"3", #"4", #"5"];
// just add more sample objects
yourDataSource = [self setsLimitForObject: yourLocalData limit: dataLimit];
[tableView reloadData];
}
}
}
- (NSArray *)setsLimitForObject:(id)object limit:(long)limit
{
if ([object isKindOfClass:[NSArray class]])
{
NSMutableArray *tempArray = [object mutableCopy];
NSRange range = NSMakeRange(0, limit);
if (tempArray.count >= range.length)
return [tempArray subarrayWithRange:range];
else
{
NSLog(#"Out of bounds");
return object;
}
} else NSLog(#"Sets Log: Cannot set limit for object %#", [object class]);
return nil;
}
#end
Try this approach, this is more like a paging...
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
[self estimatedTotalData];
}
- (void)estimatedTotalData
{
long currentRow = ((NSIndexPath *)[[YourTableView indexPathsForVisibleRows] lastObject]).row;
// 25 here is the initial data count
long estimateDataCount = 25;
while (currentRow > estimateDataCount)
{
estimateDataCount+=25;
}
dataLimit = estimateDataCount;
if (dataLimit == currentRow+1)
{
dataLimit+=25;
if (dataLimit != estimateDataCount)
{
//[self requestForData]; or load necessary data
// take not that dataLimit is the total data that must be displayed.
NSArray *yourLocalData = #[#"1", #"2", #"3", #"4", #"5"];
// just add more sample objects
yourDataSource = [self setsLimitForObject: yourLocalData limit: dataLimit];
[yourTable reloadData];
}
}
}
Update:
- (NSArray *)setsLimitForObject:(id)object limit:(long)limit
{
if ([object isKindOfClass:[NSArray class]])
{
NSMutableArray *tempArray = [object mutableCopy];
NSRange range = NSMakeRange(0, limit);
if (tempArray.count >= range.length)
return [tempArray subarrayWithRange:range];
else
{
NSLog(#"Out of bounds");
return object;
}
} else NSLog(#"Sets Log: Cannot set limit for object %#", [object class]);
return nil;
}
You can use below code for your cellForRowAtIndexPath,
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"newFriendCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [mainArray objectAtIndex:indexPath.row];
if (indexPath.row % 5 == 0) { // this if loop will get execute at every fifth row
// if you are loading data from API response then call API here and add next set of data into your existing array.
// then just reload your tableview by it's name e.g. [theTableView reloadData];
}
return cell;
}
and for your numberOfRowsInSection, instead of fixed 5 rows, just use mainArray.count like below,
- (NSInteger)tableView:(UITableView *)theTableView numberOfRowsInSection:(NSInteger)section
{
return mainArray.count;
}
I'm trying to implement a UISearchBar in a custom UITableViewController and done programmatically (not using IB). I got the search function to work and return the correct fields, but it is displaying the searched cells over the full list cells:
As you can see, the new searched field is scrollable and selectable. Its just not removing the old cells.
here is my .h file:
#interface TestTableViewController : UITableViewController <UISearchBarDelegate, UISearchDisplayDelegate>
#property (strong, nonatomic) NSArray *boundaries;
#end
.m file:
#import "TestTableViewController.h"
#import "Boundary.h"
#interface TestTableViewController ()
#property (strong, nonatomic) UISearchDisplayController *searchController;
#property (strong, nonatomic) NSMutableArray *filteredBoundaries;
#end
#implementation TestTableViewController
-(instancetype) initWithStyle:(UITableViewStyle)style {
self = [super initWithStyle:style];
if (self) {
self.filteredBoundaries = [NSMutableArray array];
}
return self;
}
-(void)viewDidLoad {
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:TRUE selector:#selector(caseInsensitiveCompare:)];
NSArray *sortDescriptors = #[sortDescriptor];
self.boundaries = [self.boundaries sortedArrayUsingDescriptors:sortDescriptors];
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
searchBar.delegate = self;
searchBar.placeholder = #"Search Fields";
searchBar.showsCancelButton = TRUE;
self.tableView.tableHeaderView = searchBar;
self.searchController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
self.searchController.delegate = self;
self.searchController.searchResultsDataSource = self;
self.searchController.searchResultsDelegate = self;
}
// ------------------------------------------------------------------------------------------------------
#pragma mark -
#pragma mark Setup Filter Data Source
-(void)filterContentForSearchText:(NSString *)searchText scope:(NSString *)scope {
[self.filteredBoundaries removeAllObjects];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name contains[c] %#", searchText];
self.filteredBoundaries = [NSMutableArray arrayWithArray:[self.boundaries filteredArrayUsingPredicate:predicate]];
}
// ------------------------------------------------------------------------------------------------------
#pragma mark -
#pragma mark Table view data source
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.searchDisplayController.searchResultsTableView) {
return self.filteredBoundaries.count;
}
else {
return self.boundaries.count;
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if (tableView == self.searchDisplayController.searchResultsTableView) {
Boundary *boundary = [self.filteredBoundaries objectAtIndex:indexPath.row];
cell.textLabel.text = boundary.name;
cell.textLabel.textColor = [UIColor blackColor];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
}
else {
Boundary *boundary = [self.boundaries objectAtIndex:indexPath.row];
cell.textLabel.text = boundary.name;
cell.textLabel.textColor = [UIColor blackColor];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
cell.userInteractionEnabled = TRUE;
}
return cell;
}
// ------------------------------------------------------------------------------------------------------
#pragma mark -
#pragma mark UISearchDisplayController Delegates
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self filterContentForSearchText:searchString scope:[[self.searchController.searchBar scopeButtonTitles] objectAtIndex:self.searchController.searchBar.selectedScopeButtonIndex]];
return TRUE;
}
#end
And how I call the table view:
TestTableViewController *tableViewController = [[TestTableViewController alloc] initWithStyle:UITableViewStylePlain];
tableViewController.boundaries = [group.boundaries allObjects];
tableViewController.contentSizeForViewInPopover = POPOVER_SIZE;
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:tableViewController];
navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
navController.navigationBar.barStyle = UIBarStyleBlack;
self.myPopoverController = [[UIPopoverController alloc] initWithContentViewController:navController];
self.myPopoverController.delegate = self;
[self.myPopoverController presentPopoverFromRect:button.frame inView:button.superview permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
Any ideas what I might be doing wrong or missing?
The problem is that UISearchDisplayController is using another UITableView rather than the view controller's own. You can verify that by logging tableView in -tableView:cellForRowAtIndexPath:.
You can use a UISearchBar without a UISearchDisplayController, to have more control over search and display logic.
Also, if your app doesn't support any version prior to iOS 8, consider using UISearchController. I haven't tried it but it seems to give you more control. Check a sample UISearchDisplayControllerhas been deprecated in iOS 8.
Try this
searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 41.0)];
[self.view addSubview:searchBar];
searchBar.delegate=self;
- (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.
if (isSearching) {
return [filteredContentList count];
}
else {
return [titlearray count];
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
SimpleTableCell *cell = (SimpleTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
if (isSearching)
{
cell.nameLabel.text = [filteredContentList objectAtIndex:indexPath.row];
cell.thumbnailImageView.image =[filteredImgArray objectAtIndex:indexPath.row];
}
else
{
cell.thumbnailImageView.image = [imagearray objectAtIndex:indexPath.row];
cell.nameLabel.text = [titlearray objectAtIndex:indexPath.row];
}
return cell;
}
- (void)searchTableList {
NSString *searchString = searchBar.text;
for (int i=0; i<titlearray.count; i++) {
NSString *tempStr=[titlearray objectAtIndex:i];
NSComparisonResult result = [tempStr compare:searchString options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [searchString length])];
if (result == NSOrderedSame)
{
[filteredContentList addObject:tempStr];
[filteredImgArray addObject:[imagearray objectAtIndex:i]];
}
}
}
#pragma mark - Search Implementation
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
isSearching = YES;
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
NSLog(#"Text change - %d",isSearching);
//Remove all objects first.
[filteredContentList removeAllObjects];
[filteredImgArray removeAllObjects];
if([searchText length] != 0) {
isSearching = YES;
[self searchTableList];
//tblContentList.hidden=NO;
}
else {
isSearching = NO;
// tblContentList.hidden=YES;
}
[tblContentList reloadData];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
NSLog(#"Cancel clicked");
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
NSLog(#"Search Clicked");
[self searchTableList];
}
I hope it's help for you
You should implement correct datasource.
Create new array of items for filtered data for first.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger count = ([filteredItems count] > 0) ? [filteredItems count] : [self.allItems count];
return count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier: #"id"];
MyCustomItem *item = ([filteredItems count] > 0) ? filteredItems[indexPath.row] : self.allItems[indexPath.row];
[self configureCell:cell forItem:item];
return cell;
}
Configure searching:
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
NSString *searchText = searchController.searchBar.text;
if ([searchText length] == 0)
{
[filteredItems removeAllObjects];
[self.tableView reloadData];
return;
}
NSMutableArray *searchResults = [self.allItems mutableCopy];
// SKIP ALL BODY OF SEARCHING
filteredPeoples = searchResults;
[self.tableView reloadData];
}
Will work pretty.
IOS 8 delegate has been deprecated not sure if that's the problem.
The method
here's [a link]https://developer.apple.com/Library/ios/documentation/UIKit/Reference/UISearchDisplayDelegate_Protocol/index.html#//apple_ref/occ/intfm/UISearchDisplayDelegate/searchDisplayControS 8 delegate has been deprecated not sure if that's the problem.
The method
try this property instead
#property(nonatomic, assign) id< UISearchResultsUpdating > searchResultsUpdater
another better link [a link]https://developer.apple.com/library/ios/samplecode/TableSearch_UISearchController/Listings/TableSearch_obj_c_TableSearch_APLResultsTableController_m.html