How to search NSMutableArray with UISearchBar? - xcode

I've searched many places but could not find the answer, so I decided to set my own question.
I populate a UITableView with data from JSON. My data structure is like this:
NSMutableArray* studentList = [(NSDictionary*)[responseString JSONValue] objectForKey:#"StudentList"];
JSON:
{
"StudentList":[
{
"StudentID":"08DH11039",
"StudentFirstName":"Nguyen Lam",
"StudentLastName":"Binhh"
},
{
"StudentID":"08DH11163",
"StudentFirstName":"Nguyen Minh",
"StudentLastName":"Duc"
},
{
"StudentID":"08DH11038",
"StudentFirstName":"Nguyen Bao",
"StudentLastName":"Khuyen"
},
{
"StudentID":"08DH11037",
"StudentFirstName":"Nguyen Tran Duy",
"StudentLastName":"Phuong"
}
]
}
Add data to UITableView:
- (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];
}
NSDictionary *student = [studentList objectAtIndex:indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"%d. %# %#", indexPath.row+1, [student objectForKey:#"StudentFirstName"], [student objectForKey:#"StudentLastName"]];
cell.textLabel.font = [UIFont fontWithName:#"Helvetica" size:15];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
I also add a UISearchBar but it didn't work:
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[searchData removeAllObjects];
NSArray *student;
for(student in studentListCopy) //take the n group (eg. group1, group2, group3)
{
NSLog(#"%#", student);
NSMutableArray *newGroup = [[NSMutableArray alloc] init];
NSString *element;
for(element in student)
NSRange range = [element rangeOfString:searchString
options:NSCaseInsensitiveSearch];
if (range.length > 0) { //if the substring match
[newGroup addObject:element]; //add the element to group
}
}
if ([newGroup count] > 0) {
[searchData addObject:newGroup];
}
}
return YES;
}
Please help me to get it work. I want to search FirstName or LastName, which are displayed in TableView.
I'm new to iOS programming. Thank you very much.

I think this will be useful to you for understanding how the NSMutableArray is used with a UISearchBar and UITableView. The Example which I got from the internet is here. Maybe this will help you in solving your problem

Related

Filtering multiple arrays

I am trying to filter 4 arrays but I can't make it work. This is a pushed tableview that uses NSString to populate. When I type something in the search bar, the search results are from 1 Array(MARLINS) even in the others. I know the problem is in -(void)filtertContentForSearchText:. What am I missing?
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView)
{
return [self.searchResults2 count];
}
else
{
if ([testName isEqualToString:#"CES"])
return [self.CES count];
if ([testName isEqualToString:#"MARLINS"])
return [self.MARLINS count];
if ([testName isEqualToString:#"DELTA 2, NAVIGATOR"])
return [self.DELTA count];
if ([testName isEqualToString:#"CREW 2002, NAVIGATOR"])
return [self.CREW count];
}
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifire = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifire];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifire];
}
if (tableView == self.searchDisplayController.searchResultsTableView)
{
cell.textLabel.text = [self.searchResults2 objectAtIndex:indexPath.row];
}
else
{
if ([testName isEqualToString:#"CES"]) {
cell.textLabel.text = [self.CES objectAtIndex:indexPath.row];
}
else if ([testName isEqualToString:#"MARLINS"]) {
cell.textLabel.text = [self.MARLINS objectAtIndex:indexPath.row];
}
else if ([testName isEqualToString:#"DELTA 2, NAVIGATOR"]) {
cell.textLabel.text = [self.DELTA objectAtIndex:indexPath.row];
}
else if ([testName isEqualToString:#"CREW 2002, NAVIGATOR"]) {
cell.textLabel.text = [self.CREW objectAtIndex:indexPath.row];
}
}
return cell;
}
#pragma Search Methods
-(void)filtertContentForSearchText:(NSString *)searchText scope:(NSString *)scope
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains[c] %#", searchText];
self.searchResults2 = [ self.MARLINS filteredArrayUsingPredicate:predicate];
self.searchResults2 = [ self.CES filteredArrayUsingPredicate:predicate];
self.searchResults2 = [ self.CREW filteredArrayUsingPredicate:predicate];
self.searchResults2 = [ self.DELTA filteredArrayUsingPredicate:predicate];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filtertContentForSearchText:searchString scope:[[self.searchDisplayController.searchBar scopeButtonTitles]objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
return YES;
}
#end
(Extracting from comments into an 'answer', edited slightly to flow together better):
You have the scope parameter that you're not using inside the filter method. Pass in something useful there from shouldReloadTableForSearchString: to know which array you should be filtering.
Look at that scope variable. If its existing value is something you can use to identify which array you want to use, then at the bare minimum, you can replicate your if...else block similar to the code you have in cellForIndexPath and only filter a particular array.

Getting reddit feed as JSON and parsing it

I'm trying to parse JSON feed from reddit.com and then display it in a tableview. The JSON looks like this:
{
kind: Listing
data: {
modhash: 3lmt2d4hq6797af804da91bde566bd067ddee68e1e7f8e0dda
children: [
{
kind: t3
data: {
domain: imgur.com
banned_by: null
media_embed: { }
subreddit: funny
selftext_html: null
selftext:
likes: null
link_flair_text: null
id: 16e9so
clicked: false
title: I left my dog unattended with the 2 year old...
num_comments: 166
score: 2213
approved_by: null
over_18: false
hidden: false
thumbnail: http://c.thumbs.redditmedia.com/DaoiOlvtdjaPBG3n.jpg
subreddit_id: t5_2qh33
edited: false
link_flair_css_class: null
author_flair_css_class: null
downs: 2481
saved: false
is_self: false
permalink: /r/funny/comments/16e9so/i_left_my_dog_unattended_with_the_2_year_old/
name: t3_16e9so
created: 1357963292
url: http://imgur.com/zGMxP
author_flair_text: null
author: ShaneNickerson
created_utc: 1357934492
media: null
num_reports: null
ups: 4694
}
...more items here
}
And here's my tableview controller code:
#import "mainRedditFunViewController.h"
#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
#define kjsonURL [NSURL URLWithString: #"http://reddit.com/r/funny/.json"
#interface mainRedditFunViewController ()
#end
#implementation mainRedditFunViewController
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://reddit.com/r/funny/.json"]];
[self performSelectorOnMainThread:#selector(fetchedData:)
withObject:data waitUntilDone:YES];
});
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (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] ;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
NSDictionary *appsdict = [jsonResults objectAtIndex:indexPath.row];
NSString *VersionString = [appsdict objectForKey:#"url"];
NSString *priceString = [appsdict objectForKey:#"author"];
NSURL *imageURL = [NSURL URLWithString:[appsdict objectForKey:#"thumbnail"]];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *imageLoad = [[UIImage alloc] initWithData:imageData];
cell.textLabel.text = [appsdict objectForKey:#"title"];
cell.detailTextLabel.text = [NSString stringWithFormat:#"URL: %# Author: $ %# USD",VersionString,priceString];
cell.imageView.image = imageLoad;
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [jsonResults count];
}
- (void)fetchedData:(NSData *)responseData {
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
jsonResults = [json objectForKey:#"data.children"];
[self.tableView reloadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
However, the output is completly empty. Is there anyway I could fix it? I tried it before with another (smaller) feed and it worked fine. I'm sure if I'm doing the JSONPath formatting correctly, since I'd look like that:
-kind
->data
->children
->data (my items)
->data
->data
...
I'd appreciate any help I get!
Im sorry that this answer is late! hope that it is still needed...
I have altered your code a little bit to access the sub levels of the returned Json results.
You certainly have the right Idea but just need a few more dictionaries in your fetchedData method. If you add these dictionaries in you method underneath your NSJSONSerialization;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:data
options:kNilOptions
error:&error];
//NSArray *Fullarray = [[NSArray alloc] initWithObjects:json, nil];
_jsonResult = [[NSMutableArray alloc] init];
NSDictionary *dataDict = [json objectForKey:#"data"];
NSDictionary *chilrenDict = [dataDict objectForKey:#"children"];
for (NSDictionary *informationFromChild in chilrenDict) {
NSLog(#"chil %#", chilrenDict);
[_jsonResult addObject:chilrenDict];
}
Then in your tableView cellForRow change your appsDict to this
NSDictionary *appsdict = [[_jsonResult objectAtIndex:indexPath.row] objectForKey:#"data"];
That should fix up the code and populate the tableView...
You can run a check on this too by checking
NSLog(#"count %i", [_jsonResult count]);
Let me know if this has been of help, happy coding. T

Custom cells - how can I separate out tweets into componentsseparatedbyString

I have a custom cell in a tableview. All connections are made. I am conducting a Twitter search. The results of this propagate a custom cell in a tableView. I would like to separate the individual tweets out into an array using componentsseparatedbystring so that I can assign these to 4 labels in my custom cell. Any help would be greatly appreciated. Here is my code.
- (void)fetchTweets
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData* data = [NSData dataWithContentsOfURL:
[NSURL URLWithString: #"https://api.twitter.com/1/statuses/public_timeline.json"]];
NSError* error;
tweets = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
});
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return tweets.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TweetCell";
customCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
// added this bit in
cell = [[customCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// THIS IS THE BIT I'M STRUGGLING WITH
// I'M GUESSING THAT THIS LINE SEPARATES THE TWEETS INTO SINGLE TWEETS?
NSDictionary *tweet = [tweets objectAtIndex:indexPath.row];
// I THEN CREATE AN ARRAY TO HOLD MY COMPONENTS OF THE TWEET SO THAT I CAN SPLIT FOR MY LABELS
NSArray *arrayForCustomCell = [[NSArray alloc] init];
arrayForCustomCell = [tweet componentsSeparatedByString:#":"];
return cell;
}
You have already parsed the results in your async call. Now, you have an array of 'tweet' dictionaries and you can grab any value like this:
NSDictionary *tweet = [tweets objectAtIndex:indexPath.row];
NSString *tweetText = [tweet valueForKey:#"text"];
NSString *tweetCountry = [tweet valueForKeyPath:#"place.country"] //Nested property
and then you just set your UILabels. You get the idea...

Invalid index path for use with UITableView when selecting rows beyond a certain number

- (int)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection: (NSInteger)section
{
return #"Substitutes";
}
- (int)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section
{
int cnt=[subArray count];
return [subArray count];
}
- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *visible = [tableView indexPathsForVisibleRows];
NSIndexPath *indexpath = (NSIndexPath*)[visible objectAtIndex:0];
if ((selectedIndexPath != nil) && (selectedIndexPath.row == indexPath.row)){
NSUInteger row = [indexPath row];
NSString *subtitle =[[subArray objectAtIndex:row] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *subDet =[[subDetArray objectAtIndex:row] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
int height = [self heightOfCellWithTitle:subtitle andSubtitle:subDet];
return(height < CONST_Cell_height ? CONST_Cell_height : height);
}
return 40.0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
static NSString *CellIdentifier = #"SearchCell";
UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
if ((selectedIndexPath != nil) && (selectedIndexPath.row == indexPath.row)){
cell = [self CreateMultilinesCell:CellIdentifier];
cell.textLabel.text=[[subArray objectAtIndex:row] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
cell.detailTextLabel.text =[[subDetArray objectAtIndex:row] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
return cell;
} else {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
cell.textLabel.text=[[subArray objectAtIndex:row] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
cell.detailTextLabel.text =[[subDetArray objectAtIndex:row] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
return cell;
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (selectedIndexPath == indexPath) {
selectedIndexPath = nil;
[table reloadData];
} else {
selectedIndexPath = indexPath;
//static NSString *CellIdentifier = #"Cell";
//UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
//cell.textLabel.text=#"test";
//cell.detailTextLabel.text =#"det Test";
[table reloadData];
}
[self.table deselectRowAtIndexPath : indexPath animated : NO];
[tableView beginUpdates];
[tableView endUpdates];
}
i implemented table view using above code.when i selecting row no. 26 v or more it
expands on selection but doesn't contract on next click.& gives me error on scroll
NSInternalInconsistencyException', reason: 'Invalid index path for use with UITableView. Index paths passed to table view must contain exactly two indices specifying the section and row. Please use the category on NSIndexPath in UITableView.h if possible.'
code work smoothly for 25 rows. where i went wrong?
i got it finaly.:) selectedIndexpath gives garbage. i replace it by self.selectedIndexpath.
i didnt get why it do so on record no. 25 onwards.But this worked for me
Use like this
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:sender.tag-1 inSection:0];
CGRect rectOfCellInTableView = [objTableView rectForRowAtIndexPath:indexPath];
CGRect rectOfCellInSuperview = [objTableView convertRect:rectOfCellInTableView toView:[objTableView superview]];

all images in table view are the same in iPhone app

I have a table view where I want a different image for each cell based on logic. Here is my cellforrowatindexpath code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:MyIdentifier] autorelease];
}
NSInteger *row = [indexPath row];
NSString *platform = [[myStringArray objectAtIndex: row];
cell.imageView.image = [self imageForInventory:platform];
return cell;
}
Here is my imageForInventory method:
- (UIImage *)imageForInventory:(NSString *)platform {
if (platform = #"Win") {
UIImage *winImage = [UIImage imageNamed:#"Vista.png"];
return winImage;
}else if (platform = #"Mac") {
UIImage *appleImage = [UIImage imageNamed:#"Apple.png"];
return appleImage;
}else if (platform = #"Linux") {
UIImage *linuxImage = [UIImage imageNamed:#"Linux.png"];
return linuxImage;
}
return nil;
}
This shows the winImage for every row ignoring the if statements. How do I get the image to set accordingly per cell?
It's probably your comparison code, to compare strings in imageForInventory use [str1 isEqualToString:str2]. You're using = which is the assignment operator right now, but even if you change it to == it wouldn't work.

Resources