I have a program that connects to a MAMP server and selects my database and displays the contents in the Xcode simulator. Right now I have 2 tabs and the data is the same for both. I want the tabs to seperate the type of data to display in each tab. (1 tab should display types of wine grape and the other displays wine countries)
I think that I have to make a class (subclass of NSObject) that pulls the data, then another view controller with a mutable array that holds the data needed for each tab but HOW do I do this? How do I create a MutableArray?
Here the code in my TableViewController.m, which connects to my database using JSON:
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *url = [NSURL URLWithString:#"http://[localhost]:8888/wine.php"]; // Modify this to match your url.
NSString *jsonreturn = [[NSString alloc] initWithContentsOfURL:url]; // Pulls the URL
NSLog(jsonreturn); // Look at the console and you can see what the restults are
NSData *jsonData = [jsonreturn dataUsingEncoding:NSUTF32BigEndianStringEncoding];
NSError *error = nil;
// In "real" code you should surround this with try and catch
NSDictionary * dict = [[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:&error];
if (dict)
{
rows = [[dict objectForKey:#"wine"] retain];
}
NSLog(#"Array: %#",rows);
[jsonreturn release];
}
Then I created another method for the tableview:
pragma mark - Table view data source
(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [rows count];
}
// Customize the appearance of table view cells.
- (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] autorelease];
}
// Configure the cell.
NSDictionary *dict = [rows objectAtIndex: indexPath.row];
//cell.textLabel.text = [dict objectForKey:#"id"];
//cell.textLabel.text = [dict objectForKey:#"wineColor"];
//cell.textLabel.text = [dict objectForKey:#"wineGrape"];
cell.textLabel.text = [dict objectForKey:#"wineCountry"];
cell.detailTextLabel.text = [dict objectForKey:#"id"];
return cell;
}
with this, the same data (the wine countries) is displayed in both Grape & Country tabs. How can I create a Mutable Array that will grab what data should be displayed in each tab?
You need the second (Grape) view controller to implement the tableView datasource and delegate methods for its own tableview, but you don't need another array, you can use your JSON dictionary, but add the proper text to labels within your cells for grapes (in the cellForRowAtIndexPath UITableView datasource method). You would use the lines above that are currently commented out to populate your labels in cells of your "Grape" table view:
//cell.textLabel.text = [dict objectForKey:#"wineColor"];
//cell.textLabel.text = [dict objectForKey:#"wineGrape"];
You could add a custom UITableViewCell or use the subtitle style and set the subtitle to color.
Related
I am new to iOS. i have to parse following JSON and display it to UITableViewCell. individual array is appearing in cell when i parse and append country item only. but all arrays for ex. rank ,country , population , flag are not appearing in cell.
how to add all rank , country , population , flag in array and put all them in cell. i have taken all them into string and then into array. and whole array i appended to main array.
following is JSON -
http://www.androidbegin.com/tutorial/jsonparsetutorial.txt
code
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSDictionary *allDataDictionary = [NSJSONSerialization JSONObjectWithData:webdata options:0 error:nil];
NSArray *arrayWorldPopulation = [allDataDictionary objectForKey:#"worldpopulation"];
for (NSDictionary *diction in arrayWorldPopulation)
{
NSString *country = [diction objectForKey:#"country"];
NSString *population = [diction objectForKey:#"population"];
NSString *flag = [diction objectForKey:#"flag"];
NSArray *temparray = [[NSArray alloc] initWithObjects:rank,country,population,flag, nil];
[array addObject:temparray];
}
[maintableView reloadData];
}
At a minimum, you need to implement tableView:numberOfRowsInSection: and tableView:cellForRowAtIndexPath in your view controller. This tells the table how many rows to expect and what each row in the table looks like. The simple code below assumes you have an array of strings and are just displaying one string per cell and should get you started. Your specific situation sounds like it may require a custom cell design. This tutorial describes how to do this in a storyboard with a custom cell class.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [array count]; //tell the UITableView how many are items are in the array
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
//stuff to make sure iOS is reusing cells rather than creating new ones
static NSString *MyIdentifier = #"MyReuseIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier];
}
NSString *itemFromArray = [array objectAtIndex:indexPath.row]; //get the item for that cell
cell.textLabel.text = itemFromArray; set the cell to display the text
return cell;
}
I'm trying to build a function that will check if a retrieved JSON value have changed (messagecount in a given conversation). I'm populating a TableView with my JSON data and I would like to store the value in a dictionary and compare them later when I do a data update.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
ConversationsModel* conversation = _feed.conversations[indexPath.row];
static NSString *identifier = #"ConversationCell";
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:identifier];
}
[self getMessageCountToDictionary:conversation.messagecount id:conversation.conversationid];
cell.textLabel.text = conversation.title;
return cell;
}
And my method to store the values in a NSMutableDictionary:
- (void)getMessageCountToDictionary:(NSNumber*)messagecount id:(NSString *)conversationid
{
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
if (conversationid != NULL) {
[dictionary setValue:conversationid forKey:[NSString stringWithFormat:#"%#", conversationid]];
[dictionary setValue:messagecount forKey:#"messageCount"];
dictionaryCopy = [dictionary mutableCopy];
}
NSLog(#"Stored in dictionary %lu", (unsigned long)dictionary.count);
}
NSLog returns 2
Well, I'm not sure if I'm on the right track here for what I intend to do. All inputs are highly appreciated.
I would recommend to use key-value observer to watch your objects changing values.
You can read more about it here:
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html
I have a split view controller for iPad with a drill-down table on the left. I am able to populate my first table view and when I click on a cell this takes me to my second table view. I am able to see a count of records returned and the actual data I expect to see in the table view output in the command widow with the NSLog command. What I don't see is the actual data in the table view. Instead I see UITableViewCellAccessoryDisclosureIndicator for each row that is returned but no actual data.
I am using xib files and I have created this file for my products I want displayed in the drill-down. In my Product.xib file I have the File's Owner Outlets as productsTableView linked to products (my UITableView control) and view linked to View. Referencing Outlets for the View have dataSource linked to products, delegate linked to products and finally view linked to File's Owner.
Am I missing something here? Like I said I get all the data back it just isn't binding to the grid.
#interface ProductViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
NSMutableArray *listOfItems;
NSMutableArray *dataArray;
IBOutlet UITableView *productsTableView;
}
#property(nonatomic, strong) IBOutlet UITableView *productsTableView;
#end
- (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];
}
// Set up the cell...
NSString *cellValue = [listOfItems objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.text = cellValue;
return cell;
}
In the interest of being thorough I will post this as well to show where I am getting my data back and how I am doing this...
-(void) connectionDidFinishLoading:(NSURLConnection *)connection {
NSError *error = nil;
// Get the JSON data from the website
id result = [NSJSONSerialization JSONObjectWithData:receivedData options:kNilOptions error:&error];
if ([result isKindOfClass:[NSArray class]]) {
for (NSArray *item in result) {
NSArray *products = [item valueForKey:#"ProductDescription"];
[dataArray addObject:products];
[listOfItems addObject:products];
}
}
else {
NSDictionary *jsonDictionary = (NSDictionary *)result;
for(NSDictionary *item in jsonDictionary)
NSLog(#"Item: %#", item);
}
[self performSelector:(#selector(refreshDisplay:)) withObject:(self.productsTableView) afterDelay:1.0];
NSLog(#"Finished");
}
My NSLog is here:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"Dictionary: %#", dataArray);
return [dataArray count];
}
Simple mixup...
NSString *cellValue = [dataArray objectAtIndex:indexPath.row];
instead of
NSString *cellValue = [listOfItems objectAtIndex:indexPath.row];
You are adding products (which is an NSArray) to listOfItems. Later in cellForRowAtIndexPath, you are saying cellValue (NSString) = [listOfItems objectAtIndex:indexPath.row] (which is potentially an `NSArray'). How would that work?
I'm new to iOS development and Objective-C programming so forgive my "noobiness".
Here's the thing, I have a function that builds an array getting data from a JSON object.
I then have a second function, responsible for filling a tableView with data from contained in my array.
Problem is, the content of this array does not seem accessible from my tableView function, even though the array has been added to my header file and implemented in the main file.
The tableView remains empty...
Do you have any idea why that is?
Here are the functions, thanks a ton for your help!
1) Array building function:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.responseData appendData:data];
//Get data
NSError *myError = nil;
NSDictionary *res = [NSJSONSerialization JSONObjectWithData:self.responseData options:NSJSONReadingMutableLeaves error:&myError];
//Extract titles
NSMutableArray *myResults = [[NSMutableArray alloc] init];
NSArray *results = [res objectForKey:#"data"];
for (NSDictionary *result in results) {
NSString *title = [result objectForKey:#"colors"];
NSLog(#"colors: %#", colors);
[myResults addObject:colors];
}
self.colorNames = myResults;
}
2) TableView filling function:
// Customize the appearance of table view cells.
- (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] autorelease];
}
//Set cell text
NSString *colorString = [self.colorNames objectAtIndex: [indexPath row]];
NSLog(#"%#",colorString);
cell.textLabel.text = colorString;
return cell;
}
are you sure you reload your table view data after receiving your json data? I would suggest a [self.tableView reloadData]; at the end of your connection:didReceiveData: method. Otherwise the method tableView:cellForRowAtIndexPath: will be called only once after you view was loaded.
Cheers,
anka
I guess you must implement something more of the UITableViewDataSource protocol.
You have to supply at least a method tableView:numberOfRowsInSection: returning the actual number of rows your table have, before the tableView:cellForRowAtIndexPath: gets called to fill in the table with your data.
Best wishes
Bruno
Is row a method of indexPath? I think it should be indexPath.row instead of [indexPath row]
I'd like to create a simple reference app that lists a group of people, their job title, and their portrait. What I have so far is the list of people and their job title. It works alright, but I think I should have done it differently.
From reading other posts, I suppose I should be using dictionaries. This is how my PList currently looks:
And this is how the important bits of my code look:
#implementation RootViewController
#synthesize staffArray, subtitleArray;
- (void)viewDidLoad
{
[super viewDidLoad];
NSString* path = [[NSBundle mainBundle] pathForResource:#"StaffData" ofType:#"plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSMutableArray *tmpNameArray = [dict objectForKey:#"Root"];
self.staffArray = [[NSMutableArray alloc] initWithArray:tmpNameArray copyItems:YES];
NSMutableArray* tmpSubtitleArray = [dict objectForKey:#"Subs"];
self.subtitleArray = [[NSMutableArray alloc] initWithArray:tmpSubtitleArray copyItems:YES];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [staffArray count];
}
// Customize the appearance of table view cells.
- (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] autorelease];
}
// Configure the cell.
cell.textLabel.text = [staffArray objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [subtitleArray objectAtIndex:indexPath.row];
return cell;
}
Using two arrays kind of defeats the purpose of OOP, I think, because in this case the people aren't connected to their job titles; they just happen to be in the same order. I'd like to create for example:
Array called Jonas, first value = job title, second value = pathToImage.png.
Another array called Andreas, etc etc etc.
What do I do?
I think that as a start, your design lacks an "Employee" object, that has data members like "Name", "JobTitle", etc... After you have this set up, just create an array of people and take whatever you need from there, by index.