Grouped Tableview From JSON Data - ios

I've been following a tutorial on YouTube and trying to expand its functionality. I figured out how to send the retrieveData method to a background thread using GCD, figured out how to use Reachability to keep the app from crashing when in Airplane Mode, and now I'm trying to change the tableview to a grouped style. After a couple of weeks I'm at my wit's end.
What I want to do is have the UITableView grouped using the key "country" to establish the groups, and any city within that country appear in the group's cells. The number of countries in the database will change, as will the number of cities.
I'm not even sure it's possible given the data structure, but if it is, I could use some suggestions.
The JSON data is structured like this:
[{"id":"1","cityName":"London","cityState":"London","cityPopulation":"8173194","country":"United Kingdom"}
Here is the .m file:
#import "CitiesViewController.h"
#import "City.h"
#import "DetailViewController.h"
#import "Reachability.h"
#define getDataUrl #"http://www.conkave.com/iosdemos/json.php"
#interface CitiesViewController ()
#end
#implementation CitiesViewController
#synthesize jsonArray, citiesArray;
- (void)viewDidLoad {
[super viewDidLoad];
//Set the title of our VC
self.title = #"Cities of the World";
//Load data
[self retrieveData];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#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.
return citiesArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
City * cityObject;
cityObject = [citiesArray objectAtIndex:indexPath.row];
cell.textLabel.text = cityObject.cityName;
cell.detailTextLabel.text = cityObject.cityCountry;
//Accessory
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
#pragma mark - Navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
if ([[segue identifier] isEqualToString:#"pushDetailView"])
{
NSIndexPath * indexPath = [self.tableView indexPathForSelectedRow];
//Get the object for the selected row
City * object = [citiesArray objectAtIndex:indexPath.row];
[[segue destinationViewController] getCity:object];
}
}
#pragma mark -
#pragma mark Class Methods
- (void) retrieveData;
{
Reachability *networkReachability = [Reachability reachabilityForInternetConnection];
NetworkStatus networkStatus = [networkReachability currentReachabilityStatus];
if (networkStatus == NotReachable) {
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"No Internet"
message:#"You must have an internet connection for this feature"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[message show];
[self.refreshControl endRefreshing];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
return;
}
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
//Retrieve the data asynchronously
dispatch_async(queue, ^{
NSURL * url = [NSURL URLWithString:getDataUrl];
NSData * data = [NSData dataWithContentsOfURL:url];
jsonArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
//Set up our cities array
citiesArray = [[NSMutableArray alloc] init];
//Loop through our jsonArray
for (int i = 0; i < jsonArray.count; i++)
{
//Create our city object
NSString * cID = [[jsonArray objectAtIndex:i] objectForKey:#"id"];
NSString * cName = [[jsonArray objectAtIndex:i] objectForKey:#"cityName"];
NSString * cState = [[jsonArray objectAtIndex:i] objectForKey:#"cityState"];
NSString * cPopulation = [[jsonArray objectAtIndex:i] objectForKey:#"cityPopulation"];
NSString * cCountry = [[jsonArray objectAtIndex:i] objectForKey:#"country"];
//Add the city object to our cities array
[citiesArray addObject:[[City alloc] initWithCityName:cName andCityState:cState andCityCountry:cCountry andcityPopulation:cPopulation andCityID:cID]];
}
//Back to main thread to update UI.use dispatch_get_main_queue() to get main thread
dispatch_sync(dispatch_get_main_queue(), ^{
//Reload our table view
[self.tableView reloadData];
});
});
}
#end

You can group the data yourself pretty easily in a few ways. One way is by using an array for ordering the countries and a dictionary to group the cities within them.
After you are done creating your City objects, you can do something like this:
// you probably want to save these as instance properties
NSMutableArray *countries = [NSMutableArray new];
NSMutableDictionary *citiesForCountries = [NSMutableDictionary new];
for(City *city in citiesArray)
{
NSString *currentCountry = city.country;
NSMutableArray *citiesInCountry = citiesForCountries[#"currentCountry"];
// first city for this country, so add it to our ordered list and create an array to populate with cities
if(! citiesInCountry)
{
[countries addObject:currentCountry];
citiesInCountry = [NSMutableArray new];
citiesForCountries[#"currentCountry"] = citiesInCountry;
}
[citiesInCountry addObject:city];
}
// Then here are some of the relevant methods on how you would use these data structures
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return countries.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSString *country = countries[section];
NSArray *cities = citiesForCountries[country];
return cities.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
City * cityObject;
NSString *country = countries[indexPath.section];
NSArray *cities = citiesForCountries[country];
cityObject = cities[indexPath.row];
cell.textLabel.text = cityObject.cityName;
cell.detailTextLabel.text = cityObject.cityCountry;
//Accessory
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}

Related

how to get the selected cell values and unselected cell values in uitableview in different array using objective c

pls check the image
i am very new to iOS how to get the selected cell values in one array and unselected cell value in the another array using by using checkmarks in objective c
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *selectedRows=[_mytableview indexPathsForSelectedRows];
indexofselectedcell = [[NSMutableArray alloc]init];
valueofselectedcell = [[NSMutableArray alloc]init];
for (int i=0; i<selectedRows.count; i++) {
[indexofselectedcell addObject:indexPath
customcell *cell = (customcell *)[_mytableview cellForRowAtIndexPath:indexPath];
NSString *test = cell.balance.text;
[valueofselectedcell addObject:test];
NSLog(#"%# the value of the selected cell value is ",valueofselectedcell);
NSArray *array = [valueofselectedcell copy];
NSNumber* sum = [array valueForKeyPath: #"#sum.self"];
NSLog(#"the sum valuie is .... %#",sum);
NSString *totalamount = [sum stringValue];
_amountlabel.text=totalamount;
NSInteger index = [valueofselectedcell indexOfObject:totalamount];
NSLog(#"%ld the index value in the array is",(long)index);
}}
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *totalamount;
if ([indexofselectedcell containsObject: indexPath])
{
NSInteger anIndex=[indexofselectedcell indexOfObject:indexPath];
[indexofselectedcell removeObjectAtIndex:anIndex];
[valueofselectedcell removeObjectAtIndex:anIndex];
NSLog(#"the value of the unselected cell value is..... %#",valueofselectedcell);
NSArray *array = [valueofselectedcell copy];
NSNumber* sum = [array valueForKeyPath: #"#sum.self"];
totalamount = [sum stringValue];
_amountlabel.text=totalamount;
totalamount= nil;
} }
Pavithra I tried sample project for your question and output.If I get unselected and selected cells in separate array,it crashed as I could not check two array in cellForRowAtIndexPath.So that I save selected and unSelected values in one array.
I created simple understandable solution.I have set values in tableview as unselected as default.If you selected(when you click the cell) it shows UITableViewCellAccessoryCheckmark and other show UITableViewCellAccessoryNone.
It works perfectly.You can easily get.
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>
#property (strong, nonatomic) IBOutlet UITableView *tableViewSelectUnSelect;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController (){
NSMutableArray *arrVal,*arrSelectedUnSelectedValues,*arrSelectedValues,*arrUnSelectedValues;
NSMutableArray *arrSubTitle;
}
#end
#implementation ViewController
#synthesize tableViewSelectUnSelect;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
arrVal= [[NSMutableArray alloc]initWithObjects:#"India",#"China",#"Korea",#"Japan",#"Peru",#"Italy",#"France",#"US",#"Dubai",#"UK",#"Nepal",nil];
arrSubTitle = [[NSMutableArray alloc]initWithObjects:#"100",#"70",#"80",#"90",#"50",#"60",#"70",#"50",#"40",#"30",#"80",nil];
arrSelectedUnSelectedValues= [[NSMutableArray alloc]init];
arrSelectedValues = [[NSMutableArray alloc]init];
arrUnSelectedValues = [[NSMutableArray alloc]init];
for(int j=0;j<[arrVal count];j++)
{
[arrSelectedUnSelectedValues addObject:#"unselected"]; //As Default it is in UnSelected State
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - UITableViewDataSource Methods
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return arrVal.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *strCell = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:strCell];
if(cell==nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:strCell];
}
if([[arrSelectedUnSelectedValues objectAtIndex:indexPath.row] isEqualToString:#"selected"])
cell.accessoryType = UITableViewCellAccessoryCheckmark;
else
cell.accessoryType = UITableViewCellAccessoryNone;
cell.textLabel.text = [arrVal objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [arrSubTitle objectAtIndex:indexPath.row];
return cell;
}
#pragma mark - UITableViewDelegate Methods
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
#try
{
CGPoint touchPoint = [cell convertPoint:CGPointZero toView:tableViewSelectUnSelect];
NSIndexPath *indexPath = [tableViewSelectUnSelect indexPathForRowAtPoint:touchPoint];
NSLog(#"The arrSelectedUnSelectedValues are %#",arrSelectedUnSelectedValues );
NSString *strValue;
if([arrSelectedUnSelectedValues count]==0)
{
for(int i=0; i<[arrVal count]; i++)
{
[arrSelectedUnSelectedValues addObject:#"unselected"];
}
}
if([[arrSelectedUnSelectedValues objectAtIndex:indexPath.row] isEqualToString:#"selected"])
{
cell.accessoryType = UITableViewCellAccessoryNone;
[arrSelectedUnSelectedValues replaceObjectAtIndex:indexPath.row withObject:#"unselected"];
strValue = cell.detailTextLabel.text;
[arrUnSelectedValues addObject:strValue];
NSLog(#"The arrUnSelectedValues are - %#",arrUnSelectedValues);
}
else
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[arrSelectedUnSelectedValues replaceObjectAtIndex:indexPath.row withObject:#"selected"];
strValue = cell.detailTextLabel.text;
[arrSelectedValues addObject:strValue];
NSLog(#"The arrSelectedValues - %#",arrSelectedValues);
}
}
#catch (NSException *exception) {
NSLog(#"The exception is-%#",exception);
}
}
#end
First when I run the application it shows like below
Then when I select values from the tableView
Then finally printed results are

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.

How to send value to anthor Page from table view iOS [duplicate]

This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 8 years ago.
I have done for parsing data from JSON and put it show in Table view.
So I want to pass data (catID and catName )to another Page it's DetailPageController
how can I do like that? the below is my code.
Thanks in advance!
#import "ViewController.h"
#interface ViewController ()
{
NSMutableArray *myObject;
// A dictionary object
NSDictionary *dictionary;
// Define keys
NSString *catName;
NSString *catID;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
catName =#"Category Name";
catID=#"Category ID";
myObject = [[NSMutableArray alloc] init];
NSData *jsonSource = [NSData dataWithContentsOfURL:
[NSURL URLWithString:#"MY_URL"]];
id jsonObjects = [NSJSONSerialization JSONObjectWithData:
jsonSource options:NSJSONReadingMutableContainers error:nil];
for (NSDictionary *dataDict in jsonObjects) {
NSString *TheCatName = [dataDict objectForKey:#"cat_name"];
NSString *TheCatID = [dataDict objectForKey:#"cat_id"];
NSLog(#"cat_name: %#",TheCatName);
NSLog(#"cat_id: %#",TheCatID);
dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
TheCatName, catName,
TheCatID, catID,
nil];
[myObject addObject:dictionary];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return myObject.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Item";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell=[[UITableViewCell alloc]initWithStyle:
UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
NSDictionary *tmpDict = [myObject objectAtIndex:indexPath.row];
NSMutableString *textcat;
textcat = [NSMutableString stringWithFormat:#"%#",
[tmpDict objectForKeyedSubscript:catName]];
NSMutableString *catid;
catid = [NSMutableString stringWithFormat:#"ID: %# ",
[tmpDict objectForKey:catID]];
cell.textLabel.text = textcat;
cell.detailTextLabel.text= catid;
return cell;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
didSelectRowAtIndexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *tmpDict = [myObject objectAtIndex:indexPath.row];
NSMutableString *catID;
catID = [NSMutableString stringWithFormat:#"%#",
[tmpDict objectForKeyedSubscript:cat_id]];
NSLog(#"didSelectRowAtIndexPath");
/*UIAlertView *messageAlert = [[UIAlertView alloc]
initWithTitle:#"Row Selected" message:#"You've selected a row" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];*/
UIAlertView *messageAlert = [[UIAlertView alloc]
initWithTitle:#"Row Selected" message:catID delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
// Display the Hello World Message
[messageAlert show];
// Checked the selected row
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
First import DetailPageController in TableviewController Class with help of following line.
#import "DetailPageController.h"
Now implement following method in your TableViewController Class
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
DetailPageController * detailPageControllerOBJ_ = [[ImageOptionViewController alloc]initWithNibName:#“XIBName bundle:nil];
detailPageControllerOBJ_.dicSelectedData = [self.arrayData objectAtIndex:indexPath.row];
[self.navigationController pushViewController:detailPageControllerOBJ_ animated:YES];
}
And in DetailPageController.h put following code.
#property (nonatomic,strong) NSDictionary * dicSelectedData;
You will get your selected data in dicSelectedData Dictionary

Pull to refresh UITableView Data

I have a pull to refresh setup. It's currently calling [self.tableView reloadData]; but It's not reloading my parsed Json data from the blogData method. Is theres something I'm missing?
My controller is like this:
//
// ARTableViewController.m
// WorldCupLive
//
// Created by Adam Rais on 14/06/2014.
// Copyright (c) 2014 Adam Rais. All rights reserved.
//
#import "ARTableViewController.h"
#import "ARModal.h"
#interface ARTableViewController ()
#end
#implementation ARTableViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.blogPost = [[ARModal alloc] init];
self.blogPost.jsonMutable = [NSMutableArray array];
for (NSDictionary *post in self.blogPost.blogData) {
ARModal *bp = [ARModal blogPostWithHome:[[post objectForKey:#"home"] objectForKey:#"text"]];
bp.away = [[post objectForKey:#"away"] objectForKey:#"text"];
bp.result = [[post objectForKey:#"result"] objectForKey:#"text"];
bp.info = [post objectForKey:#"info"];
bp.homeImage = [[post objectForKey:#"homeimage"] objectForKey:#"src"];
[self.blogPost.jsonMutable addObject:bp];
}
[self randomBackgroundImage];
self.tableView.contentInset = UIEdgeInsetsMake(0.0f, -10.0f, 0.0f, 0.0f);
// Initialize Refresh Control
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
// Configure Refresh Control
[refreshControl addTarget:self action:#selector(refresh:) forControlEvents:UIControlEventValueChanged];
// Configure View Controller
[self setRefreshControl:refreshControl];
}
-(void)randomBackgroundImage {
UIImage *image = self.blogPost.imageUI;
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
self.tableView.backgroundView = imageView;
self.tableView.backgroundView.layer.zPosition -= 1;
}
- (void)refresh:(id)sender
{
NSLog(#"Refreshing");
[self.tableView reloadData];
[self randomBackgroundImage];
// End Refreshing
[(UIRefreshControl *)sender endRefreshing];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#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.
return [self.blogPost.jsonMutable count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
// Configure the cell...
ARModal *post = [self.blogPost.jsonMutable objectAtIndex:indexPath.row];
NSData *imageData = [NSData dataWithContentsOfURL:post.jsonURL];
UIImage *image = [UIImage imageWithData:imageData];
cell.textLabel.text = [[[[[post.home stringByAppendingString:#" "]stringByAppendingString:#" "] stringByAppendingString:post.bst] stringByAppendingString:#" "] stringByAppendingString:post.away];
cell.detailTextLabel.text = post.info;
cell.imageView.image = image;
cell.backgroundColor = [UIColor colorWithWhite:1.000 alpha:0.000];
return cell;
}
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not 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) {
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#end
And my modal:
//
// ARModal.m
// WorldCupLive
//
// Created by Adam Rais on 14/06/2014.
// Copyright (c) 2014 Adam Rais. All rights reserved.
//
#import "ARModal.h"
#implementation ARModal
-(id)initWithHome:(NSString *)home {
self = [super init];
if (self) {
_home = home;
_away = nil;
_result = nil;
_info = nil;
_homeImage = nil;
}
return self;
}
+(id)blogPostWithHome:(NSString *)home {
return [[self alloc] initWithHome:home];
}
-(NSArray *)blogData {
NSURL *jsonURL = [NSURL URLWithString:#"http://www.kimonolabs.com/api/2nfgfo2s?apikey=1a1f5f323969d5157af8a8be857026c2"];
NSData *jsonData = [NSData dataWithContentsOfURL:jsonURL];
NSError *jsonError = nil;
NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&jsonError];
NSArray *jsonArray = [[jsonDictionary objectForKey:#"results"] objectForKey:#"collection1"];
if (blogData == nil) {
blogData = jsonArray;
}
return blogData;
}
-(NSURL *)jsonURL {
return [NSURL URLWithString:self.homeImage];
}
-(NSString *)bst {
NSString *sentence = self.result;
NSString *word = #"-";
NSString *wordTwo = #"00.00";
NSString *wordThree = #"01.00";
NSMutableArray *bstArray = [NSMutableArray array];
if ([sentence rangeOfString:word].location != NSNotFound) {
NSLog(#"Found the string");
[bstArray addObject:sentence];
} else if ([sentence rangeOfString:wordTwo].location != NSNotFound) {
NSLog(#"time is 23:00");
[bstArray addObject:#"23:00"];
} else if ([sentence rangeOfString:wordThree].location != NSNotFound) {
NSLog(#"time is 00:00");
[bstArray addObject:#"00:00"];
} else {
float floatOne = [sentence floatValue];
float floatFinal = floatOne - 1.000000;
NSString *str = [NSString stringWithFormat:#"%f", floatFinal];
NSString *bstFinal = [str substringToIndex:[str length] - 4];
[bstArray addObject:bstFinal];
}
return [bstArray objectAtIndex:0];
}
-(UIImage *)imageUI {
NSArray *imageArray = #[[UIImage imageNamed:#"Algeria"],[UIImage imageNamed:#"Argentina"],[UIImage imageNamed:#"Australia"],[UIImage imageNamed:#"Belgium"],[UIImage imageNamed:#"Bosnia-Herzegovina"],[UIImage imageNamed:#"Switzerland"],[UIImage imageNamed:#"Uruguay"],[UIImage imageNamed:#"USA"],[UIImage imageNamed:#"Brazil"],[UIImage imageNamed:#"Cameroon"],[UIImage imageNamed:#"Chile"],[UIImage imageNamed:#"Colombia"],[UIImage imageNamed:#"Costa Rica"],[UIImage imageNamed:#"Côte d'Ivoire"],[UIImage imageNamed:#"Croatia"],[UIImage imageNamed:#"Ecuador"],[UIImage imageNamed:#"England"],[UIImage imageNamed:#"France"],[UIImage imageNamed:#"Germany"],[UIImage imageNamed:#"Ghana"],[UIImage imageNamed:#"Greece"],[UIImage imageNamed:#"Honduras"],[UIImage imageNamed:#"Iran"],[UIImage imageNamed:#"Italy"],[UIImage imageNamed:#"Japan"],[UIImage imageNamed:#"Mexico"],[UIImage imageNamed:#"Netherlands"],[UIImage imageNamed:#"Nigeria"],[UIImage imageNamed:#"Portugal"],[UIImage imageNamed:#"Russia"],[UIImage imageNamed:#"South Korea"],[UIImage imageNamed:#"Spain"]];
int random = arc4random_uniform(imageArray.count);
return [imageArray objectAtIndex:random];
}
#end
When you call the -[UITableView reloadData] method you are telling the tableview to refresh ints content based on the source you already gave him, but he doesnt change the source. In some cases you refresh you datasource and you need to refresh the UITableView so you call the -[UITableView reloadData]. What you need to do is to first refresh you data and the refresh the view, so the view uses your new data.
Use the the same way you got the data from your modal to refresh it.
self.blogPost.jsonMutable = [NSMutableArray array];
for (NSDictionary *post in self.blogPost.blogData) {
ARModal *bp = [ARModal blogPostWithHome:[[post objectForKey:#"home"] objectForKey:#"text"]];
bp.away = [[post objectForKey:#"away"] objectForKey:#"text"];
bp.result = [[post objectForKey:#"result"] objectForKey:#"text"];
bp.info = [post objectForKey:#"info"];
bp.homeImage = [[post objectForKey:#"homeimage"] objectForKey:#"src"];
[self.blogPost.jsonMutable addObject:bp];
}
Then execute the -[UITableView reloadData], but now he is going to refresh using the refreshed data that you got from your modal.
If you need something else, comment.
-[UITableView reloadData] doesn't actually reload your data. It tells the table that you've reloaded the data, and now you need the table view to reload.
So before you call reloadData you should do:
self.blogPost.jsonMutable = [NSMutableArray array];
for (NSDictionary *post in self.blogPost.blogData) {
ARModal *bp = [ARModal blogPostWithHome:[[post objectForKey:#"home"] objectForKey:#"text"]];
bp.away = [[post objectForKey:#"away"] objectForKey:#"text"];
bp.result = [[post objectForKey:#"result"] objectForKey:#"text"];
bp.info = [post objectForKey:#"info"];
bp.homeImage = [[post objectForKey:#"homeimage"] objectForKey:#"src"];
[self.blogPost.jsonMutable addObject:bp];
}
Also as this chunk of code only uses information provided by ARModal, you should probably put it in a method in ARModal

iOS search bar not showing results

*Update: This actually works, the style for my custom cell hasn't come across and so the cell looks blank. How then do I get the searchResultsTableView to use my custom cell?
I have implemented a search bar in my table view. Searching, filtering all work when I debug, but when I enter characters into the search bar, the results do not load or show. This is everything I'm doing:
#interface InviteTableViewController ()<UIAlertViewDelegate, UISearchBarDelegate, UISearchDisplayDelegate>
#property(nonatomic, strong) NSNumber *contactsCount;
#property(nonatomic, strong) InviteTableViewCell *selectedCell;
#property(strong, nonatomic) NSMutableArray *filteredContactArray;
#property (weak, nonatomic) IBOutlet UISearchBar *contactsSearchBar;
#end
#implementation InviteTableViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void) extractAllContacts: (ABAddressBookRef) addressBookRef{
NSMutableArray *contactsArray = [NSMutableArray array];
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBookRef);
CFIndex numberOfPeople = ABAddressBookGetPersonCount(addressBookRef);
for(int i = 0; i < numberOfPeople; i++){
ABRecordRef person = CFArrayGetValueAtIndex( allPeople, i );
NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonFirstNameProperty));
if(firstName){
ABMultiValueRef emails = ABRecordCopyValue(person, kABPersonEmailProperty);
for (CFIndex i = 0; i < ABMultiValueGetCount(emails); i++) {
NSString *email = (__bridge_transfer NSString *) ABMultiValueCopyValueAtIndex(emails, i);
MyUser *amUser = [[MyUser alloc] init];
amUser.email =email;
NSString *fullName =[NSString stringWithFormat:#"%# %#",firstName, (__bridge NSString *)(ABRecordCopyValue(person, kABPersonLastNameProperty))];
amUser.fullName = fullName;
[contactsArray addObject:amUser];
}
}
}
NSLog(#"================================count ============= %d", [contactsArray count]);
contactsArray = [contactsArray sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSDate *first = [(MyUser*) a fullName];
NSDate *second = [(MyUser*)b fullName];
return [first compare:second];
}];
self.inviteContactsArray = contactsArray;
self.filteredContactArray = [NSMutableArray arrayWithCapacity:[contactsArray count]];
[self.tableView reloadData];
}
- (void)viewDidLoad
{
[super viewDidLoad];
_contactsCount = [NSNumber numberWithInt:0];
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, NULL);
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
if (granted) {
[self extractAllContacts: addressBookRef];
[self.tableView reloadData];
} else {
NSString *message = [NSString stringWithFormat:#"You have not given permission to use your address book. Please allow in settings "];
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:#"Enable Contacts" message:message delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
});
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
// The user has previously given access, add the contact
[self extractAllContacts:addressBookRef];
}
else {
// The user has previously denied access
// Send an alert telling user to change privacy setting in settings app
}
[self.tableView reloadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (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.filteredContactArray count];
} else {
return [self.inviteContactsArray count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"InviteCell";
InviteTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if ( cell == nil ) {
cell = [[InviteTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
MyUser *person = nil;
if (tableView == self.searchDisplayController.searchResultsTableView)
{
person = [self.filteredContactArray objectAtIndex:[indexPath row]];
NSMutableArray *tempArray = self.filteredContactArray;
}
else
{
person = [self.inviteContactsArray objectAtIndex:[indexPath row]];
}
//InviteTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
person = [self.inviteContactsArray objectAtIndex:indexPath.row];
cell.nameLabel.text = person.fullName;
cell.emailLabel.text = person.email;
return cell;
}
#pragma mark Content Filtering
-(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
// Update the filtered array based on the search text and scope.
// Remove all objects from the filtered search array
[self.filteredContactArray removeAllObjects];
// Filter the array using NSPredicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.fullName contains[c] %#",searchText];
self.filteredContactArray = [NSMutableArray arrayWithArray:[self.inviteContactsArray filteredArrayUsingPredicate:predicate]];
}
#pragma mark - UISearchDisplayController Delegate Methods
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
#end
This is what it looks like:
Agree with #rdelmar.
BUT There is a kind of tricky behavior in TableView, if you change the code in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
....
InviteTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
....
}
to
InviteTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if added the prefix "self." your code should works fine.
and
if ( cell == nil )
{
cell = [[InviteTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
is unnecessary. it will just create a standard "Subtitle Cell" for you that seems not you want, just remove them.
If you want to use the same cell for your main table and the search results table, you should make the cell in a xib (or you could do it entirely in code). In viewDidLoad, register the nib for both table views,
- (void)viewDidLoad {
[super viewDidLoad];
[self.searchDisplayController.searchResultsTableView registerNib:[UINib nibWithNibName:#"InviteTableViewCell" bundle:nil] forCellReuseIdentifier:#"InviteCell"];
[self.tableView registerNib:[UINib nibWithNibName:#"InviteTableViewCell" bundle:nil] forCellReuseIdentifier:#"inviteCell"];
}
In cellForRowAtIndexPath, you can do something like this,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
InviteTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"InviteCell" forIndexPath:indexPath];
MyUser *person = ([tableView isEqual:self.tableView])? self.inviteContactsArray[indexPath.row] : self.filteredContactArray[indexPath row];
cell.nameLabel.text = person.fullName;
cell.emailLabel.text = person.email;
return cell;
}
If you've already setup your cell in the storyboard, you can copy and paste it into an empty xib file, so you don't have to set it up all over again. You can delete the cell from your storyboard table view since you will be getting the cell from the xib file instead.
Below line in viewdidload should do the trick
self.searchDisplayController.searchResultsTableView.rowHeight = self.tableView.rowHeight

Resources