How to control multiple arrays when using search in UITableView - ios

I have four array videoName, ActorName, VideoID, ActorID. I combined videoName & ActorName to make a single array "title", and same with VideoID & ActorID to make array "IDs"
In short,
title = ActorName + videoName
IDs = ActorID + VideoID
here is my code,
Tableview Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
return self.searchResults.count;
} else {
return self.title.count;
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = #"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
cell.backgroundColor = [UIColor clearColor];
cell.textLabel.textColor = [UIColor whiteColor];
cell.imageView.frame = CGRectMake(0,0,32,32);
if (tableView == self.searchDisplayController.searchResultsTableView) {
cell.textLabel.text = [self.searchResults objectAtIndex:indexPath.row];
cell.imageView.image = [UIImage imageNamed:[img objectAtIndex:indexPath.row]];
cell.textLabel.textColor = [UIColor blackColor];
} else {
cell.textLabel.text = [self.title objectAtIndex:indexPath.row];
cell.imageView.image = [UIImage imageNamed:[img objectAtIndex:indexPath.row]];
}
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
Search Methods
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF beginswith[c] %#", searchText];
// NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"contains[c] %#", searchText];
self.searchResults = [self.title filteredArrayUsingPredicate:predicate];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
Requirement
Now, first i need to get that which row was selected, actor or Video, secondly actorID or VideoID. It was easy if there was no search bar, because after the search all rows restored again with new data plus rows are populated from "title" not "IDs" so how can i get IDs when user select the row.

create a NSObject subclass for this Item.h and Item.m with 3 properties for name and id like,
in Item.h
typedef enum : NSInteger {
ItemTypeVideo,
ItemTypeActor,
} ItemType;
#interface Item : NSObject
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *itemId;
#property (nonatomic, strong) NSString *imageName;
#property (nonatomic, assign) ItemType itemType;
#end
by above code we are creating a class whose object can hold values defined in properties.
since an object of Item class can hold name, id, image name and type of video/actor, we can set these values of 1 video/actor to one object.
here we have multiple vides/actor elements, so we need an array of Item objects each one holding details of one video/actor like
Item *videoItem = [[Item alloc] init];
videoItem.name = videoName;
videoItem.itemId = videoId;
videoItem.imageName = videoImageName;
videoItem.itemType = ItemTypeVideo;
create for all items in videoName array and actor array. Add both this to a common dataArray like,
[self.dataArray addObejct:videoItem];
and
Item *actorItem = [[Item alloc] init];
actorItem.name = actorName;
actorItem.itemId = actorId;
actorItem.imageName = actorImageName;
actorItem.itemType = ItemTypeActor;
similarly [self.dataArray addObejct:actorItem];
and in cellForRowAtIndexPath:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//other stuff
Item *currentItem = nil;
if (tableView == self.searchDisplayController.searchResultsTableView) {
currentItem = [self.searchResults objectAtIndex:indexPath.row];
} else {
currentItem = [self.dataArray objectAtIndex:indexPath.row];
}
cell.textLabel.text = currentItem.name;
cell.imageView.image = [UIImage imageNamed:currentItem.imageName];
//rest stuff
}
finally in search,
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name beginswith[c] %#", searchText];
// NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"contains[c] %#", searchText];
self.searchResults = [self.dataArray filteredArrayUsingPredicate:predicate];
}
So in any case,
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Item *currentItem = nil;
if (tableView == self.searchDisplayController.searchResultsTableView) {
currentItem = [self.searchResults objectAtIndex:indexPath.row];
} else {
currentItem = [self.dataArray objectAtIndex:indexPath.row];
}
//all details will be in currentItem
}

Related

UISearchBar displays no results while typing in text

When my user searches an item in my UISearchBar, results are displayed if the full word typed into the bar matches one of the results. E.g. if "Panda" is typed in, Panda pops up in the tableView results. However if "Pan" is typed in, no results are shown. How can I make my search results filter work as the user is typing? Panda should be displayed even if just "pan" is typed in.
My filter code currently looks like this:
.m
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
NSPredicate *resultPredicate = [NSPredicate
predicateWithFormat:#"SELF contains[cd] %#",
searchText];
searchResults = [self.neighbourData filteredArrayUsingPredicate:resultPredicate];
}
/*
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
} */
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [searchResults count];
} else {
return [self.neighbourData count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *NetworkTableIdentifier = #"sidebarCell";
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
sidebarCell *cell = (sidebarCell *)[tableView dequeueReusableCellWithIdentifier:NetworkTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"sidebarCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
if (tableView == self.searchDisplayController.searchResultsTableView) {
NSDictionary *userName = [searchResults objectAtIndex:indexPath.row];
[[cell username] setText:[userName objectForKey:#"first name"]];
NSDictionary *userlast = [searchResults objectAtIndex:indexPath.row];
[[cell lastName] setText:[userlast objectForKey:#"last name"]];
NSDictionary *userBio = [searchResults objectAtIndex:indexPath.row];
[[cell userDescription] setText:[userBio objectForKey:#"userbio"]];
NSString *profilePath = [[searchResults objectAtIndex:indexPath.row] objectForKey:#"photo_path"];
[cell.usermini sd_setImageWithURL:[NSURL URLWithString:profilePath]];
NSLog(#"This is profilePath %#",profilePath);
} else {
NSDictionary *userName = [self.neighbourData objectAtIndex:indexPath.row];
[[cell username] setText:[userName objectForKey:#"first name"]];
NSDictionary *userlast = [self.neighbourData objectAtIndex:indexPath.row];
[[cell lastName] setText:[userlast objectForKey:#"last name"]];
NSDictionary *userBio = [self.neighbourData objectAtIndex:indexPath.row];
[[cell userDescription] setText:[userBio objectForKey:#"userbio"]];
NSString *profilePath = [[self.neighbourData objectAtIndex:indexPath.row] objectForKey:#"photo_path"];
[cell.usermini sd_setImageWithURL:[NSURL URLWithString:profilePath]];
NSLog(#"This is profilePath %#",profilePath);
}
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 115;
}
neighbourData Log:
[12663:3559832] This is the neighbourdata (
{
address = "1144 fake street";
city = Las Vegas;
"first name" = Panda;
"last name" = Zoo;
"photo_path" = "none";
}
try this
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
NSPredicate * predicate =[NSPredicate predicateWithFormat:#"%K contains[cd] %#",#"first name", searchText];
searchResults = [self.neighbourData filteredArrayUsingPredicate:resultPredicate];
if searchResults.count == 0
{
NSPredicate * predicate =[NSPredicate predicateWithFormat:#"%K contains[cd] %#",#"last name",searchText];
searchResults = [self.neighbourData filteredArrayUsingPredicate:resultPredicate];
}
// add predicates for other keys also if you want
[tableView reloadData];
}
Suggestions:
Avoid spaces between words of keys ('first name' this is not recommended, 'firstName' recommended)
And save values in all lowercase ('Panda', 'Zoo' its better to save as 'panda','zoo' this will make search more simpler)
You need to reload your tableview after your data filtered and also remove exist object for searchResult array.
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
NSPredicate * predicate =[NSPredicate predicateWithFormat:#"first name = %#", searchText];
searchResults = [self.neighbourData filteredArrayUsingPredicate:resultPredicate];
[tableView reloadData];
}
Try out this predicate block:
NSPredicate* p = [NSPredicate predicateWithBlock:
^BOOL(id obj, NSDictionary *d) {
NSString* s = obj;
NSStringCompareOptions options = NSCaseInsensitiveSearch;
return ([s rangeOfString:sbc.searchBar.text
options:options].location != NSNotFound);
}];
self.filteredStates = [states filteredArrayUsingPredicate:p];
Meanwhile checkout this Link.
Hope it helps.
The method "filterContentForSearchText" should be in "textDidChange" method of UISearchBar. Where are you writing this method currently?
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
#interface ViewController : UIViewController <UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource, UISearchDisplayDelegate, UISearchBarDelegate>
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property (strong, nonatomic) IBOutlet UISearchDisplayController *searchDisplayController;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.neighbourData = #[#"Apple", #"App", #"Bell"];
NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"filterCell"];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
NSPredicate *resultPredicate = [NSPredicate
predicateWithFormat:#"SELF contains[cd] %#",
searchText];
self.searchResults = [self.neighbourData filteredArrayUsingPredicate:resultPredicate];
}
/*
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
} */
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [self.searchResults count];
} else {
return [self.neighbourData count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:#"filterCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"filterCell"];
}
if (tableView == self.searchDisplayController.searchResultsTableView) {
cell.textLabel. text = [self.searchResults objectAtIndex:indexPath.row];
} else {
cell.textLabel. text = [self.neighbourData objectAtIndex:indexPath.row];
}
return cell;
#end

search bar method for array of dictionarys in ios using NSPredicate method

I am new in IOS and I am creating a search bar for UITableView. It is working fine when I use an array directly, but when I have an array with a dictionary it's not working.
I have an array of dictionaries:
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableDictionary *person1 = [NSMutableDictionary dictionaryWithDictionary:#{
#"Name" : #"john",
#"Age" : #"10"
}];
NSMutableDictionary *person2 = [NSMutableDictionary dictionaryWithDictionary:#{
#"Name" : #"piter",
#"Age" : #"22"
}];
NSMutableDictionary *person3 = [NSMutableDictionary dictionaryWithDictionary:#{
#"Name" : #"rams",
#"Age" : #"23"
}];
self.person = [[NSMutableArray alloc]initWithObjects:person1,person2,person3 ,nil];
}
I have print those dictionary name on UITableView.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *simpleTableIdentifier = #"myCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [[self.personobjectAtIndex:indexPath.row]objectForKey:#"Name"];
return cell;
}
It will give me list of names in UITableView. I used a search bar and I want to search for specific words and have them show on my UITableView, but its not working using this code:
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
if([searchText length] == 0){
self.isfiltered = NO;
}
else{
self.isfiltered = YES;
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"SELF contains[cd] %#",searchText];
filteredList = [self.person filteredArrayUsingPredicate:resultPredicate];
}
[self.mytable reloadData];
}
You need to change your data source array while searching .
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.isfiltered ? filteredList.count : self.person.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *simpleTableIdentifier = #"myCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier]; }
cell.textLabel.text = [[ self.isfiltered ? filteredList : self.person objectAtIndex:indexPath.row]objectForKey:#"Name"]; }
return cell;
}
you need to change 'SELF' -> 'Name'.
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
if([searchText length] == 0){
self.isfiltered = NO;
}
else{
self.isfiltered = YES;
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"Name contains[cd] %#",searchText];
filteredList = [self.person filteredArrayUsingPredicate:resultPredicate];
}
[self.mytable reloadData];
}
Then change in your table array.
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if (self.isfiltered)
return filteredList.count;
else
return self.person.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *simpleTableIdentifier = #"myCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier]; }
if (self.isfiltered)
cell.textLabel.text = [[self.isfiltered objectAtIndex:indexPath.row]objectForKey:#"Name"];
else
cell.textLabel.text = [[self.person objectAtIndex:indexPath.row]objectForKey:#"Name"];
return cell;
}

Add Alphabetical Headers to UITableView with a sorted array

I'm sorting my array by last name alphabetically. I'd like to separate this into sections with the appropriate header above each section (A, B, C, etc.).
Here's what I've tried below:
// Here is where I refresh the data and sort it based on last name
- (void)refreshData {
[[PCMSSessionManager sharedSession] refreshPCMSDataWithCompletion:^(BOOL success, NSString *errorMessage, id resultObject) {
if (success) {
NSLog(#"yay!");
self.membersArray = [[PCMSSessionManager sharedSession] memberArr];
// Let's sort the array
self.sortedArray = [self.membersArray sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSString *first = [(PCMSMember*)a lastName];
NSString *second = [(PCMSMember*)b lastName];
return [first compare:second];
}];
[self.tableView reloadData];
} else {
NSLog(#"boooo!!!!");
}
}];
}
- (NSDictionary *)indexedMembers
{
NSMutableDictionary *indexedContacts = [NSMutableDictionary new];
for (PCMSMember *member in self.sortedArray)
{
NSString *sortString = member.lastName;
NSString *sortLetter = [sortString substringToIndex:1];
/* see if that letter already exists as an index */
BOOL foundKey = NO;
for (NSString *key in [indexedContacts allKeys])
{
if ([key isEqualToString:sortLetter])
{
foundKey = YES;
}
}
NSMutableArray *valueArray;
if (foundKey)
{
valueArray = [((NSArray *)indexedContacts[sortLetter]) mutableCopy];
}
else
{
valueArray = [NSMutableArray new];
}
[valueArray addObject:member];
indexedContacts[sortLetter] = [valueArray copy];
}
return [indexedContacts copy];
}
// Here's my table data
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [[[self indexedMembers] allKeys] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSDictionary *indexedContacts = [self indexedMembers];
NSArray *myKeys = [indexedContacts allKeys];
NSString *key = myKeys[section];
return [((NSArray *)[self indexedMembers][key]) count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"cellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
// Configure the cell...
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
if (self.isPhysician == YES) {
NSString *key = [[self indexedMembers] allKeys][indexPath.section];
PCMSMember *currentMember = ((NSArray *)[self indexedMembers][key])[indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"%# %#", currentMember.firstName, currentMember.lastName];
}
return cell;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [[self indexedMembers] allKeys][section];
}
UPDATE:
This is getting me closer to what I want.
The data is loading, it's being grouped properly and the headers are showing.
But it's not in alphabetical order.
How can I improve this code to show alphabetically?
It's showing in alphabetical order in my console, just not in the app.
The NSMutableDictionary is unordered by definition. It is not the natural choice if you rely on the order of the stored objects. I suggest you to use NSMutableArray instead. To store the tableview data for each section you can use this mini class
#interface MembersWithSameInitial : NSObject
#property (strong) NSString* initial;
#property (strong) NSMutableArray<PCMSMember*>* members;
#end
#implementation MembersWithSameInitial
#end
After you have sorted the members, all the data for the tableview can be produced with this before tableView reload.
NSMutableArray<MembersWithSameInitial*>* groupedMembers = [[NSMutableArray alloc] init];
for (PCMSMember* member in sortedArray) {
NSString* inicial = [member.lastName substringToIndex:1];
MembersWithSameInitial* last = [groupedMembers lastObject];
if (last && [last.initial isEqualToString:inicial]) {
[last.members addObject:member];
} else {
MembersWithSameInitial* newGroup = [[MembersWithSameInitial alloc] init];
newGroup.initial = inicial;
newGroup.members = [[NSMutableArray alloc] initWithObjects:member, nil];
[groupedMembers addObject:newGroup];
}
}
Since the structure of groupedMembers fits to a grouped tableView, the dataSource methods will have trivial implementations. Assuming, that you have stored groupedMembers in a property.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.groupedMembers.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.groupedMembers[section].members.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//...
PCMSMember *currentMember = self.groupedMembers[indexPath.section].members[indexPath.row];
//...
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return groupedMembers[section].initial;
}
Suggestion:
Create two properties
#property NSMutableArray *keys; // for the letters in alphabetical order
#property NSMutableDictionary *indexedContacts; // same as your implementation.
In the method refreshData call the method to create the data source and then reload the table view on the main thread.
Actually you don't need the properties memberArray and sortedArray anymore. The sorted array is passed to the method to create the data source.
- (void)refreshData {
[[PCMSSessionManager sharedSession] refreshPCMSDataWithCompletion:^(BOOL success, NSString *errorMessage, id resultObject) {
if (success) {
NSLog(#"yay!");
self.membersArray = [[PCMSSessionManager sharedSession] memberArr];
// Let's sort the array
NSArray *sortedArray = [self.membersArray sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSString *first = [(PCMSMember*)a lastName];
NSString *second = [(PCMSMember*)b lastName];
return [first compare:second];
}];
[self indexMembers:sortedArray];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
} else {
NSLog(#"boooo!!!!");
}
}];
}
The method indexMembers initializes the properties keys and indexedContacts and creates the data source.
- (void)indexMembers:(NSArray *)sortedMembers
{
self.keys = [[NSMutableArray alloc] init];
self.indexedContacts = [[NSMutableDictionary alloc] init];
for (PCMSMember *member in sortedMembers)
{
NSString *sortString = member.lastName;
NSString *sortLetter = [sortString substringToIndex:1];
/* see if that letter already exists as an index */
NSArray *keyArray = self.indexedContacts[sortLetter];
NSMutableArray *valueArray;
if (keyArray) {
// array for key exists, use it
valueArray = [keyArray mutableCopy];
} else {
// array for key does not exist, create a new one
valueArray = [NSMutableArray new];
// and add the letter to keys
[self.keys addObject:sortLetter];
}
[valueArray addObject:member];
self.indexedContacts[sortLetter] = [valueArray copy];
}
}
numberOfSectionsInTableView returns the number of keys
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.keys.count;
}
numberOfRowsInSection gets the appropriate array for the given section and returns the number of items.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSString *letter = self.keys[section];
NSArray *memberArray = self.indexedContacts[letter];
return memberArray.count;
}
In cellForRowAtIndexPath use the method dequeueReusableCellWithIdentifier: forIndexPath: to get always a valid cell. Then like in numberOfRowsInSection get the actual member array and populate the label.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"cellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
// Configure the cell...
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
if (self.isPhysician == YES) {
NSString *letter = self.keys[indexPath.section];
NSArray *memberArray = self.indexedContacts[letter];
PCMSMember *currentMember = memberArray[indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"%# %#", currentMember.firstName, currentMember.lastName];
}
return cell;
}
titleForHeaderInSection simply returns the letter for the section
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return self.keys[section];
}
You're calling indexedMembers too much. This is very expensive.
I couldn't test the code, maybe there is a self or something else missing but you get an impression of the workflow.

UISearchBar + array of objects + NSpredicate

Would you please tell me why my SearchBar doesn´t work in my UITableViewController?
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
NSPredicate *predicate = [NSPredicate
predicateWithFormat:#"SELF.TitleInside contains[c] %#",
searchText];
filteredArray = [HelpList filteredArrayUsingPredicate:predicate];
}
Why
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier =#"Cell";
TableViewCell_Rts *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell){
cell = [[TableViewCell_Rts alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.accessoryType = UITableViewCellAccessoryNone;
CellObject *NewIndex = nil;
if (tableView == self.tableView) {
NewIndex = [HelpList objectAtIndex:indexPath.row];
cell.TitleLabel2.text = NewIndex.TitleInside;
cell.DescriptionLabel2.text = NewIndex.DescriptionInside;
} else {
NewIndex= [filteredArray objectAtIndex:indexPath.row];
cell.TitleLabel2.text = NewIndex.TitleInside;
cell.DescriptionLabel2.text = NewIndex.DescriptionInside;
}
CellObject is a NSObject:
#interface CellObject : NSObject
#property (nonatomic, strong) NSString *ImageInside;
#property (nonatomic, strong) NSString *TitleInside;
#end
When i run the application, my tableview looks populated. Then, when i write inside the search bar, the table doesn´t show the results of the search.
Thanks ¡

"Unrecognized Selector Sent to Instance" - Error When Adding Search Bar [duplicate]

This question already has answers here:
Error: unrecognized selector sent to instance
(2 answers)
Closed 8 years ago.
I just added a search bar to my iPhone app which should search through a TableViewController of songs. However, when I run my app on my iPhone, it freezes with a black screen and I get this error: unrecognized selector sent to instance on this line:
MPMediaItem *rowItem = [songs objectAtIndex:indexPath.row];
in this block:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
if (tableView == self.searchDisplayController.searchResultsTableView) {
songs = [searchResults objectAtIndex:indexPath.row];
} else {
songs = [songs objectAtIndex:indexPath.row];
}
MPMediaItem *rowItem = [songs objectAtIndex:indexPath.row];
cell.textLabel.text = [rowItem valueForProperty:MPMediaItemPropertyTitle];
cell.detailTextLabel.text = [rowItem valueForProperty:MPMediaItemPropertyArtist];
return cell;
}
This is my implementation code:
#implementation SongsViewController
{
NSArray *searchResults;
NSArray *songs;
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
MPMediaQuery *songsQuery = [MPMediaQuery songsQuery];
songs = [songsQuery items];
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [searchResults count];
} else {
return [songs count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
if (tableView == self.searchDisplayController.searchResultsTableView) {
songs = [searchResults objectAtIndex:indexPath.row];
} else {
songs = [songs objectAtIndex:indexPath.row];
}
MPMediaItem *rowItem = [songs objectAtIndex:indexPath.row];
cell.textLabel.text = [rowItem valueForProperty:MPMediaItemPropertyTitle];
cell.detailTextLabel.text = [rowItem valueForProperty:MPMediaItemPropertyArtist];
return cell;
}
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"name contains[c] %#", searchText];
searchResults = [songs filteredArrayUsingPredicate:resultPredicate];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
I do not understand what's wrong? The error is: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MPConcreteMediaItem objectAtIndex:]: unrecognized selector sent to instance 0x178221e20'.
Any help would be much appreciated!
Change this code:
if (tableView == self.searchDisplayController.searchResultsTableView) {
songs = [searchResults objectAtIndex:indexPath.row];
} else {
songs = [songs objectAtIndex:indexPath.row];
}
MPMediaItem *rowItem = [songs objectAtIndex:indexPath.row];
to this:
MPMediaItem *rowItem;
if (tableView == self.searchDisplayController.searchResultsTableView) {
rowItem = [searchResults objectAtIndex:indexPath.row];
} else {
rowItem = [songs objectAtIndex:indexPath.row];
}
Issue is happening because of the following line:
songs = [songs objectAtIndex:indexPath.row];
You are assigning MPMediaItem to the NSArray object. And next time when you try to use [songs objectAtIndex:indexPath.row]; It'll crash.

Resources