I'm trying to load a data from a JSON file. I've added this file to my Project Files in Xcode 4.6, but every time I run my code, I get empty cells in the TableView, with no data at all, even though I've declared a properly for each label and assigned a value for them from the JSON file.
I have created two classes: events.h and .m, jsonloader.h and .m, and imported them into my main view controller.
Here's a sample of my JSON data:
{
"Events": [
{
"id": "1",
"title": "parr jazz presents zoe chiotis",
"performingArtists": "Zoe Chiotis",
"day": "Tuesday",
"date": "2013-12-03",
"lastUpdated": "2013-12-03",
"startingTime": "8:00:00 PM",
"endingTime": "1:00:00 AM",
"venue": "STUDIO2",
"location": {
"streetAddress": "33-45 Parr Street",
"postCode": "L1 4JN"
},
"music genre": "Jazz",
"information": "ZOE CHIOTIS is a singer/songwriter/guitarist based in Manchester. ",
"image": "http://bandonthewall.org/images/content/large/zoe-chiotis-1764.jpg",
"thumb": "http://swingbands.co.uk/wp-content/zoechiotis.jpg"
},
...
]}
This is event.m:
#implementation JSONLoader
- (NSArray *)eventsFromJSONFile:(NSURL *)url {
// Create a NSURLRequest with the given URL
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:30.0];
// Get the data
NSURLResponse *response;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
// Now create a NSDictionary from the JSON data
NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
// Create a new array to hold the locations
NSMutableArray *events = [[NSMutableArray alloc] init];
// Get an array of dictionaries with the key "Events"
NSArray *array = [jsonDictionary objectForKey:#"Events"];
// Iterate through the array of dictionaries
for(NSDictionary *dict in array) {
// Create a new event object for each one and initialise it with information in the dictionary
Events *dataevents = [[Events alloc] initWithJSONDictionary:dict];
// Add the Location object to the array
[events addObject:dataevents];
}
// Return the array of Location objects
return events;
}
and in my mainViewController.m I included this:
#implementation MV_HomeViewController {
NSArray *_events;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
// Create a new JSONLoader with a local file URL
JSONLoader *jsonLoader = [[JSONLoader alloc] init];
NSURL *url = [[NSBundle mainBundle] URLForResource:#"EventsData" withExtension:#"json"];
// Load the data on a background queue...
// As we are using a local file it's not really necessary, but if we were connecting to an online URL then we'd need it
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
_events = [jsonLoader eventsFromJSONFile:url];
// Now that we have the data, reload the table data on the main UI thread
[self.myTableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
});
}
#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 [_events count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"eventCell";
MV_CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
if (cell == nil) {
cell = [[MV_CustomCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
// Configure the cell...
//[[cell textLabel] setText:_eventType];
Events *event = [_events objectAtIndex:indexPath.row];
cell.TitleLabel.text = event.title;
cell.GenreLabel.text = event.musicGenre;
return cell;
}
Does anybody know what the problem is here?
Related
Xcode problem. I have a nsmutablearray that is pulling json objects. Example Company: Name, state, address, phone number, etc.
I am pulling the info just fine. And I want to display 1 of each state in a table view. It works fine but shows multibles of the same state. But I only want to show 1 of each state. I am using some code but it does not return any states. I have seen a lot of examples and this should work but it returns nothing. If I skip this code below it does show all states. i have also tried a for loop. And tried array to NSSet. Nothing is working. Any Ideas???
My problem is with this code...
//Create states only array...remove duplicate states here
NSArray *statesArray = [companies valueForKeyPath:#"#distinctUnionOfObjects.state"];
return statesArray;
Here is my whole code. Please help been struggling with this for a week.
#interface StatesTableViewController ()
#property (nonatomic) NSString *name;
#property (nonatomic) NSString *state;
#end
#implementation StatesTableViewController
NSArray *companies;
NSArray *statesArray;
- (void)viewDidLoad {
[super viewDidLoad];
NSString *address = #"http://www.companiesFeed";
NSURL *url = [[NSURL alloc] initWithString:address];
//laod the data on a background queue..
//if we were connecting to a an online url then we need it
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
companies = [self readCompanies:url];//, statesSet = [self readCompanies:url];
//now that we have the data, reload the table data on the main ui thread
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
});
}
//new code
- (NSArray *)readCompanies:(NSURL *)url {
//create a nsurlrequest with the given Url
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:
NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:30.0];
//get the data
NSURLResponse *response;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
//now create a nsdictionary from the json data
NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:data
options:0 error:nil];
//create a new array to hold the comanies
NSMutableArray *companies = [[NSMutableArray alloc] init];
//get an array of dictionaries with the key "company"
NSArray *array = [jsonDictionary objectForKey:#"companies"];
//iterate throught the array of dictionaries
for (NSDictionary *dict in array) {
//create a new company object with information in the dictionary
Company *company = [[Company alloc] initWithJSONDictionary:dict];
//add the Company object to the array
[companies addObject:company ];
}
//Create states only array...remove duplicate states here
NSArray *statesArray = [companies valueForKeyPath:#"#distinctUnionOfObjects.state"];
return statesArray;
//return companies;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark -table view controller methods
//change uniqueValue errors to companies
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger) section {
//return[companies count];
return [statesArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellID = #"CellIDState";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil){
//single line on table view
//cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellID];
// dual line on table view
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID];
}
//edit single state
//Company *company = [companies objectAtIndex:indexPath.row];
Company *company = [statesArray objectAtIndex:indexPath.row];
//cell.textLabel.text = company.company_id;
cell.textLabel.text = company.state;
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#",company.companyName];
//adds cheveron to tableviewl
[cell setAccessoryType: UITableViewCellAccessoryDisclosureIndicator];
return cell;
}
#pragma mark - navigation
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
}
#end
I was able to get the unique list of states by using a predicate and a block to check a set for existing states. Like so:
NSMutableArray *statesArray = [NSMutableArray array];
[companies filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
Company *dict = (Company *)evaluatedObject;
BOOL seen = [statesArray containsObject:dict];
if (!seen) {
[statesArray addObject:dict];
}
return !seen;
}]];
NSLog(#"unique states: %#", statesArray);
Where the companies array looks like this:
{[{
"company_id": "22",
"entityformSubmissionID": "22",
"companyName": "house of waffles",
"companySlogan": " where your home is!",
"address1": "123 here",
"address2": "thre",
"city": "everywhere",
"state": "CA",
"zipCode": "94531",
"phoneNumber": "777-777-7777",
"email": "test#test.com",
"additionalCompanyInfo": "all additional company info is going here",
"sales": "There are no sales!",
"rentalTerms": "Terms is dont break our stuff jerks!",
"companyLogo": "/16x16icon.png"
}]
This question already has answers here:
Removing duplicates from array based on a property in Objective-C
(8 answers)
Closed 7 years ago.
ok new to objective c.
I have my app going to a web site and pulling company data. Company name address etc. I want to display the state from each company. But I only want one of each state shown. For example if I have CA,CA,CA,AZ,AZ,AZ,NY. I only want to display on my tableview CA,AZ,NY. I am have tried distinctUnionOfObjects, but I think I am using it wrong. any help?
#import "StatesTableViewController.h"
#interface StatesTableViewController ()
#end
#implementation StatesTableViewController
NSArray *companies;
- (void)viewDidLoad {
[super viewDidLoad];
NSString *address = #"http://www.Feed";
NSURL *url = [[NSURL alloc] initWithString:address];
//laod the data on a background queue..
//if we were connecting to a an online url then we need it
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
companies = [self readCompanies:url];
//now that we have the data, reload the table data on the main ui thread
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
});
}
//new code
- (NSArray *)readCompanies:(NSURL *)url {
//create a nsurlrequest with the given Url
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:
NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:30.0];
//get the data
NSURLResponse *response;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
//now create a nsdictionary from the json data
NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:data
options:0 error:nil];
//create a new array to hold the comanies
NSMutableArray *companies = [[NSMutableArray alloc] init];
//get an array of dictionaries with the key "company"
NSArray *array = [jsonDictionary objectForKey:#"companies"];
//iterate throught the array of dictionaries
for (NSDictionary *dict in array) {
//create a new company object with information in the dictionary
Company *company = [[Company alloc] initWithJSONDictionary:dict];
//add the Company object to the array
[companies addObject:company];
}
//return the array of Company objects
return companies;
}
//trying to get 1 state here? should i create a new array?
//added code to show 1 of each state. companies array now uniquevalues
//NSArray* uniqueValues = [companies valueForKeyPath:[NSString stringWithFormat:#"distinctUnionOfObjects.%#",#"state"]];
//or
//static NSArray *uniqueValues = nil;
//if (uniqueValues == nil){
// uniqueValues = [NSArray arrayWithArray:[companies valueForKeyPath:[NSString stringWithFormat:#"distinctUnionOfObjects.%#",#"state"]]];
//}
//or
//companies = [companies valueForKeyPath:#"#distinctUnionOfObjects.state"];
//end added code
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark -table view controller methods
//change uniqueValue errors to companies
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger) section {
// return [uniqueValues count];
return [companies count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellID = #"CellIDState";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil){
//single line on table view
//cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellID];
// dual line on table view
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID];
}
//Company *company = [uniqueValues objectAtIndex:indexPath.row];
Company *company = [companies objectAtIndex:indexPath.row];
//cell.textLabel.text = company.company_id;
cell.textLabel.text = company.state;
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#",company.companyName];
//adds cheveron to tableviewl
[cell setAccessoryType: UITableViewCellAccessoryDisclosureIndicator];
return cell;
}
#pragma mark - navigation
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
}
#end
Suppose you have a Company object with the following interface:
#interface Company : NSObject
#property (nonatomic) NSString *name;
#property (nonatomic) NSString *state;
#end
Next, let's say you do the following:
// Creating & adding a few companies
Company *company1 = [Company new];
company1.name = #"Some Company";
company1.state = #"CA";
Company *company2 = [Company new];
company2.name = #"Some Company";
company2.state = #"CA";
Company *company3 = [Company new];
company3.name = #"Some Company";
company3.state = #"CA";
Company *company4 = [Company new];
company4.name = #"Some Company";
company4.state = #"AZ";
Company *company5 = [Company new];
company5.name = #"Some Company";
company5.state = #"AZ";
self.companies = #[company1, company2, company3, company4, company5];
NSArray *uniqueStates = [self.companies valueForKeyPath:#"#distinctUnionOfObjects.state"];
NSSet *uniqueStatesSet = [NSSet setWithArray:[self.companies valueForKey:#"state"]];
The uniqueStates array & uniqueStatesSet set will both contain two objects, #"CA" and #"AZ" (two ways of getting a unique set objects).
NSArray *companies = …;
NSOrderedSet *states = [NSOrderedSet orderedSetWithArray:[companies valueForKey:#"state"]];
If you have an ordered list of unique items, you should use an ordered set to model it.
I have my own json file "list.json" for a list of sample informations like below. My json file is
located inside of Xcode, I want to show my information to the table, would you please give me some hints and help for this implementation, how can I parse local json and load information in table.
[
{
"number": "1",
"name": "jon"
},
{
"number": "2",
"name": "Anton"
},
{
"number": "9",
"name": "Lili"
},
{
"number": "7",
"name": "Kyle"
},
{
"display_number": "8",
"name": "Linda"
}
]
you can create a custom class which inherits from UITableViewController.
The code to read the contents of list.json file into an array is:
NSString * filePath =[[NSBundle mainBundle] pathForResource:#"list" ofType:#"json"];
NSError * error;
NSString* fileContents =[NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
if(error)
{
NSLog(#"Error reading file: %#",error.localizedDescription);
}
self.dataList = (NSArray *)[NSJSONSerialization
JSONObjectWithData:[fileContents dataUsingEncoding:NSUTF8StringEncoding]
options:0 error:NULL];
And the header file is:
#import <UIKit/UIKit.h>
#interface TVNA_ReadingDataTVCViewController : UITableViewController
#end
The implementation is:
#import "TVNA_ReadingDataTVCViewController.h"
#interface TVNA_ReadingDataTVCViewController ()
#property NSArray* dataList;
#end
#implementation TVNA_ReadingDataTVCViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self readDataFromFile];
[self.tableView reloadData];
}
-(void)readDataFromFile
{
NSString * filePath =[[NSBundle mainBundle] pathForResource:#"list" ofType:#"json"];
NSError * error;
NSString* fileContents =[NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
if(error)
{
NSLog(#"Error reading file: %#",error.localizedDescription);
}
self.dataList = (NSArray *)[NSJSONSerialization
JSONObjectWithData:[fileContents dataUsingEncoding:NSUTF8StringEncoding]
options:0 error:NULL];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.dataList.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
id keyValuePair =self.dataList[indexPath.row];
cell.textLabel.text = keyValuePair[#"name"];
cell.detailTextLabel.text=[NSString stringWithFormat:#"ID: %#", keyValuePair[#"number"]];
return cell;
}
#end
Finally, on your story board, assign this class as the custom class of your Table View Controller. Hope this helps.
I've been stuck on a problem for a few days now. I have searched the internet and found many answers, but nothing that seems to work - I may not grasp how to modify my own code.
I have a JSON connection which I make a dictionary. This all works very well when I dont have a multilevel dictionary, but as soon as I have:
{
"Table": [
{
"MENUID": 1072.0,
"MENUDESC": "HOME ",
"PARENTMENUID": null,
"NAVIGATETO": "content.aspx?item=1072&pid=0",
"NAVIGATETO2": "default.aspx?item=1072&pid=0",
"PROTECTED": null,
"parentmenuid2": null
},
{
"MENUID": 1073.0,
"MENUDESC": "PRODUCTS & SERVICES",
"PARENTMENUID": null,
"NAVIGATETO": "#",
"NAVIGATETO2": "default.aspx?item=1073&pid=0",
"PROTECTED": null,
"parentmenuid2": null
}
]
}
I adapt my code as follows:
- (void)fetchTweets
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData* data = [NSData dataWithContentsOfURL:
[NSURL URLWithString: #"http://adhoc.nyxtek.co.za/spfjsonws/default2.aspx"]];
NSError* error;
menuItems = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&error];
NSArray * allKeys = [menuItems allKeys];
NSLog(#"Count : %d", [allKeys count]);
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
});
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return menuItems.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TweetCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSDictionary *tweet = (NSDictionary *)[menuItems objectForKey:#"Table"];
NSArray * allKeys = [tweet allKeys];
NSLog(#"Count : %d", [allKeys count]);
//NSDictionary *tweet = [tweets objectAtIndex:indexPath.row];
NSString *text = [tweet objectForKey:#"MENUDESC"];
NSString *name = [tweet objectForKey:#"MENUID"];
cell.textLabel.text = text;
cell.detailTextLabel.text = [NSString stringWithFormat:#"by %#", name];
return cell;
}
Specifically this line of code is not working:
NSDictionary *tweet = (NSDictionary *)[menuItems objectForKey:#"Table"];
My first count of the outer dictionary is 1 which is correct, but my second count of the new above dictionary is 0 which is wrong.
I have applied much of this from researching previous questions as I understand the importance of research, but I still cant seem to find a specific fault.
Any assistance would be appreciated.
Table is an array (of dictionaries):
"Table": [
...
]
So the code should be:
NSArray *tweet = (NSArray *)[menuItems objectForKey:#"Table"];
I have a view controller with a table view. in each cell of the table view, i have an image which is fetched from the net - but many of them have the same image. so, what i'm doing currently is storing the fetched images in a NSCache object. it happens this way:
- (void)fetchAvatarForUser:(NSString *)uid completion:(void (^)(BOOL))compBlock
{
if (!imageCache) {
imageCache = [[NSCache alloc] init];
}
if (!avatarsFetched) {
avatarsFetched = [[NSMutableArray alloc] initWithCapacity:0];
}
if ([avatarsFetched indexOfObject:uid] != NSNotFound) {
// its already being fetched
} else {
[avatarsFetched addObject:uid];
NSString *key = [NSString stringWithFormat:#"user%#",uid];
NSString *path = [NSString stringWithFormat:#"users/%#/avatar",uid];
[crudClient getPath:path parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"%#",[operation.response allHeaderFields]);
UIImage *resImage = [UIImage imageWithData:[operation responseData]];
[imageCache setObject:resImage forKey:key];
compBlock(YES);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Got error: %#", error);
compBlock(NO);
}];
}
}
- (UIImage *)getAvatarForUser:(NSString *)uid
{
NSString *key = [NSString stringWithFormat:#"user%#",uid];
NSLog(#"Image cache has: %#",[imageCache objectForKey:key]);
return [imageCache objectForKey:key];
}
imageCache is an instance variable, and also avatarsFetched, crudClient is an AFHTTPClient object.
and, in the table view:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
PostCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[PostCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Post *curPost = [displayedPosts objectAtIndex:indexPath.section];
cell.nickname.text = [curPost nickname];
UIImage *avatarImage = [self.delegateRef.hangiesCommunicator getAvatarForUser:curPost.userID];
if (avatarImage) {
cell.avatar.image = avatarImage;
NSLog(#"Its not null");
} else {
cell.avatar.image = [UIImage imageNamed:#"20x20-user-black"];
}
}
self.delegateRef.hangiesCommunicator returns the object (which is a retained property of the app delegate) with the imageCache as an instance variable, and the two methods at the top.
When i scroll, i see the #"Its not null" in the console, yet i don't see the fetched image but the default 20x20-user-black image. does anybody have an idea, why is this happening? what am i doing wrong?
thanks!
Your code is missing some things. I can't see where you ever call the fetchAvatarForUser:completion: method on your hangiesCommunicator and your tableView:cellForRowAtIndexPath: method is not returning the cell, so I don't think the code you posted will compile cleanly.