I'm creating a simple iPad app with DetailViewController. Everything works great, but when I try to use multiple level JSON, it doesn't work anymore the app crashes.
I retrieve and loop through data:
-(void) retrieveData{
NSURL * url = [NSURL URLWithString:getDataURL];
NSData * data = [NSData dataWithContentsOfURL:url];
jsonArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
fruitArray = [[NSMutableArray alloc] init];
//loop through jsonarray
for(int i =0;i < jsonArray.count;i++){
NSString * cName = [[jsonArray objectAtIndex:i] valueForKey:#"cityName"];
NSString * cFruit = [[jsonArray objectAtIndex:i] valueForKey:#"fruit"];
//add object to fruitArray array
[fruitArray addObject:[[Fruits alloc]initWithCityDocumentName:cName andFruit:cFruit]];
}
//reload table view
[self.tableView reloadData];
}
using json:
[{
"id": "1",
"cityName": "London",
"fruit":"Apple"
}, {
"id": "2",
"cityName": "Berlin",
"fruit":"Pear"
}]
and then I set the labels(I hook them up from the storyboard/NIB):
- (void)setLabels{
cityNameLabel.text = currentCity.documentName;
fruitLabel.text = currentCity.documentFruit;
}
All this above work fine.
But as soon as I create multiple values in the JSON for fruits, it does not work!
New JSON:
[{
"id": "1",
"cityName": "London",
"fruit":
["Apple", "Pear", "Orange", "Lemon"]
}, {
"id": "2",
"cityName": "Berlin",
"fruit":
["Mango", "Melon", "Tomatoe", "Avocado"]
}]
It looks to me that I need to somehow programatically create the labels and loop over them? Basically, I need to see multiple values in the Detail View Controller for each id
How can I do it?
I really need a help here :(
Thank you.
EDIT: I was now able to create an Array rather than strings but When I'm creating buttons from them it won't let me add the title based on what's in array:
NSMutableArray * cFruit = [[jsonArray objectAtIndex:i] valueForKey:#"fruit"];
and then:
- (void)setLabels{
for(int i=0;i<=currentCity.documentFruit.count;i++){
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self
action:#selector(setLabels)
forControlEvents:UIControlEventTouchUpInside];
//below is my error - looks like it doesn't like setting the titles from array
[button setTitle:[currentCity.documentFruit objectAtIndex:i] forState:UIControlStateNormal];
button.frame = CGRectMake(20.0, ButtonHeightPlusOffsetBetweenButtons * i , 280.0, 40.0);
//Set Tag for future identification
[button setTag:i];
[self.view addSubview:button];
}
}
Here I am providing you complete code, to do so
#import "ViewController.h"
#import "FruitsBO.h"
#interface ViewController ()
#property (strong, nonatomic) IBOutlet UITableView *tblFruit;
#property (nonatomic, strong) NSMutableArray *arrFruitData;
#end
#implementation ViewController
#synthesize arrFruitData;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
arrFruitData = [[NSMutableArray alloc] init];
[self loadLocalJson];
}
-(void)loadLocalJson
{
NSString *pathStringToLocalFile = [[NSBundle mainBundle] pathForResource:#"Fruit" ofType:#"json"];
NSError *deserializingError;
NSURL *localFileURL = [NSURL fileURLWithPath:pathStringToLocalFile];
NSData *contentOfLocalFile = [NSData dataWithContentsOfURL:localFileURL];
NSArray *objects = [NSJSONSerialization JSONObjectWithData:contentOfLocalFile
options:NSJSONReadingAllowFragments
error:&deserializingError];
[self parseFruit:objects];
}
-(void)parseFruit:(NSArray *)arrFruits
{
for (NSDictionary *dictTemp in arrFruits) {
FruitsBO *fruit = [[FruitsBO alloc] init];
fruit.fruitID = [dictTemp objectForKey:#"id"];
fruit.cityName = [dictTemp objectForKey:#"cityName"];
fruit.arrFruit = [dictTemp objectForKey:#"fruit"];
[arrFruitData addObject:fruit];
fruit = nil;
}
[self.tblFruit reloadData];
}
#pragma mark - TableView Delegate -
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [self.arrFruitData count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
FruitsBO *obj = [self.arrFruitData objectAtIndex:section];
return [obj.arrFruit count];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 50;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 30;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
FruitsBO *obj = [self.arrFruitData objectAtIndex:section];
return obj.cityName;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"fruitIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
FruitsBO *objTemp = [self.arrFruitData objectAtIndex:indexPath.section];
cell.textLabel.text = [objTemp.arrFruit objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Here my Json
[{
"id": "1",
"cityName": "London",
"fruit":
["Apple", "Pear", "Orange", "Lemon"]
}, {
"id": "2",
"cityName": "Berlin",
"fruit":
["Mango", "Melon", "Tomatoe", "Avocado"]
},{
"id": "2",
"cityName": "Austin",
"fruit":
["Mango"]
}]
Here my output
The fruitArray array is a local variable in your method. It is never stored anywhere. Whatever you put into it, it will never have any effect.
BTW.
Use a for loop like for (NSDictionary* dict in jsonArray), avoiding the slow indexing operation every time.
You assume that the key fruit contains a string, when it contains an array. That is going to crash your program sooner or later.
Don't use valueForKey, use objectForKey. Eventually you will get very surprising results with valueForKey.
After you updated your JSON, you receive not NSString object, but NSArray for the:
NSString * cFruit = [[jsonArray objectAtIndex:i] valueForKey:#"fruit"];
So you need to do something like this:
NSArray *fruitsArray = [[jsonArray objectAtIndex:i] valueForKey:#"fruit"];
NSString *cFruit = [fruitsArray componentsJoinedByString:#","];
Related
I have an issue with the below service.
{
"DataTable": [
{
"EmpTable": [
{
"Name": "Rakesh",
"Finaldata": "5",
"data": "One Year Free",
"heading": "HR",
},
{
"Name": "Roshan",
"Finaldata": "1",
"data": "1 Month",
"heading": "Software",
},
{
"Name": "Ramesh",
"Finaldata": "5",
"data": "3 Month",
"heading": "Admin",
},
]
}
]
}
Only getting the details of Ramesh from the above output, Remaining data doesn't display in my table view. Below is my code what i have tried from the above service. Please help to find out the issue. TIA
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _empArr.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
EmpCell *cell = (MembershipCell *) [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"MembershipCell" owner:self options:nil];
for (id currentObject in topLevelObjects){
if ([currentObject isKindOfClass:[UITableViewCell class]]){
cell = (EmpCell *) currentObject;
}
}
}
profiledict = [_empArr objectAtIndex:indexPath.row];
for (NSDictionary *temp in profiledict) {
cell.lblName.text = [temp objectForKey:#"Name"];
cell.lblFinaldata.text = [temp objectForKey:#"Finaldata"];
cell.lbldata.text = [temp objectForKey:#"data"];
cell.lblheading.text = [temp objectForKey:#"heading"];
}
return cell;
}
- (void)jsonData:(NSDictionary *)jsonDict
{
NSMutableArray *jsonArr;
NSMutableDictionary *dict;
[SVProgressHUD dismiss];
jsonArr=[jsonDict objectForKey:#"DataTable"];
if (![jsonArr isEqual:[NSNull null]]) {
_empArr=[[NSMutableArray alloc] init];
for (int i=0; i<jsonArr.count; i++) {
dict=[jsonArr objectAtIndex:i];
[_empArr addObject:[dict objectForKey:#"EmpTable"]];
}
[self.tableView reloadData];
}
else
{
[SVProgressHUD showErrorWithStatus:#"Something went wrong"];
[self.tableView reloadData];
}
}
You are adding Whole EmpTable array as an object in array. So there is only one object in array. Thats why only one cell will be added on tableView. Try to extract array objects from EmpTable array.
In - (void)jsonData:(NSDictionary *)jsonDict method
Replace
[_empArr addObject:[dict objectForKey:#"EmpTable"]];
with
[_empArr addObjectsFromArray:[dict objectForKey:#"EmpTable"]];
and in cellForRowAtIndexPath
Replace
profiledict = [_empArr objectAtIndex:indexPath.row];
for (NSDictionary *temp in profiledict) {
cell.lblName.text = [temp objectForKey:#"Name"];
cell.lblFinaldata.text = [temp objectForKey:#"Finaldata"];
cell.lbldata.text = [temp objectForKey:#"data"];
cell.lblheading.text = [temp objectForKey:#"heading"];
}
With
profiledict = [_empArr objectAtIndex:indexPath.row];
cell.lblName.text = [profiledict objectForKey:#"Name"];
cell.lblFinaldata.text = [profiledict objectForKey:#"Finaldata"];
cell.lbldata.text = [profiledict objectForKey:#"data"];
cell.lblheading.text = [temp objectForKey:#"heading"];
Hope this helps.
_empArr.count will always be 1 because you have only one "EmpTable" object inside. Even if you fix that, then in cellForRowAtIndexPath's for (NSDictionary *temp in profiledict) you cycle through all the array and never stop, so each time it will be the last object to fill your cell fields.
This is my json data. Here it is Restaurant name coming one and line name coming 2 some times line name coming more then how to print the data in custom cell.please. help me
"currency": "$",
"state": "sale",
"total": 243.1,
"name": "a1238",
"restaurant_name": "\"Food Court\" Biergarten",
"date": "2016-10-16 07:52:07",
"table_no": null,
"so_id": 238,
"lines": [
{
"line_status": "pending",
"line_id": 2536,
"line_price": 1,
"line_qty": 1,
"line_name": "Käse"
},
{
"line_status": "pending",
"line_id": 2579,
"line_price": 7.8,
"line_qty": 2,
"line_name": "3 Musketiere (3x verschiedene Hefe 0,3l)"
},
Try like this:
First get all values from your response in NSMutableArray what you want
#interface ViewController ()
{
NSMutableArray *restaurentsNamesArray;
NSMutableArray *linesArray;
NSMutableArray *linesCountArray;
}
After that in viewDidLoad add values to those mutable arrays which you got from your response
- (void)viewDidLoad {
[super viewDidLoad];
restaurentsNamesArray = [[NSMutableArray alloc]init];
linesArray = [[NSMutableArray alloc]init];
linesCountArray = [[NSMutableArray alloc]init];
NSError *error;
// Do the stuff for get response from url here.
// And give that request below.
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
NSDictionary *main = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSDictionary *result = [main valueForKey:#"result"];
NSArray *saleorders = [result valueForKey:#"saleorders"];
for (NSDictionary *dict in saleorders){
[restaurentsNamesArray addObject:[dict valueForKey:#"restaurant_name"]];
[linesArray addObject:[dict valueForKey:#"lines"]];
}
NSLog(#"%#",restaurentsNamesArray);
NSLog(#"%#",linesArray);
}
Now all you want is implement table view delegate methods like below:
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [restaurentsNamesArray count];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
NSArray *array;
if (linesArray.count > section){
array = [linesArray objectAtIndex:section];
}
return array.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [[UITableViewCell alloc]init];
NSArray *array;
array = [linesArray objectAtIndex:indexPath.section];
NSDictionary *dict = [array objectAtIndex:indexPath.row];
cell.textLabel.text = [dict valueForKey:#"line_name"];
cell.detailTextLabel.text = [dict valueForKey:#"line_id"];
return cell;
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [restaurentsNamesArray objectAtIndex:section];
}
Here I'm just populating restaurant names in tableView section header as NSString.
If you want exactly like android what you shown above you have to implement below methods instead of -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section this method
- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, 50)];
[headerView setBackgroundColor:[UIColor darkGrayColor]];
UILabel *tempLabel=[[UILabel alloc]initWithFrame:CGRectMake((headerView.frame.size.width/2)-47,-32,300,94)];
tempLabel.backgroundColor=[UIColor clearColor];
tempLabel.shadowColor = [UIColor blackColor];
tempLabel.shadowOffset = CGSizeMake(0,2);
tempLabel.textColor = [UIColor whiteColor];
tempLabel.font = [UIFont fontWithName:#"Helvetica" size:17.0];
tempLabel.font = [UIFont boldSystemFontOfSize:17.0];
tempLabel.text= [restaurentsNamesArray objectAtIndex:section];
[headerView addSubview:tempLabel];
return headerView;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
{
return 35;
}
Like the same way I'm just populating lineName in cell.textLabel
If you want to do more , just create custom tableViewCell and create layout how you want.
that's it.
Cheers.
Use your restaurant array for section
numberOfSectionsInTableView{}
and your "lines": [{}] array for
numberOfRowsInSection{}
You may get better idea from code mentioned below
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number restaurant count
return [restaurantArray count];
}
and for multiple rows considering you have restaurant as object:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of lines count.
return [objRestaurant.Lines count];
}
First of all create an array of Restaurant type an fetch the data from json and add it into an array just like that
var RestaurantArray = [Restaurant]()
for index in 0..<JSON["data"].count
{
let address = String(JSON["data"][index]["Address"])
let CityId = JSON["data"][index]["CityId"].int
let Description = String(JSON["data"][index]["Description"])
let Name = String(JSON["data"][index]["Name"])
//create an object of Restaurant type and map the data into object and then add it into array that we have created .
var RestaurantModel:Restaurant?
RestaurantModel.address = address
RestaurantModel.cityID = cityId
RestaurantModel.Description = Description
RestaurantArray.append(RestaurantModel)
}
now use this array in your tableview
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return RestaurantArray.count
}
I hope this will make a lot of sense to you
Cheers
i'm trying to fill a tableview with a Json response this is the Json that i'm reading from the callback
{
"Categories": {
"Beer": [
{
"id": "3",
"nombre": "Bud ligth",
"precio": "10",
"categoriaid": "3",
"url": "false"
}
],
"Whiskey": [
{
"id": "2",
"nombre": "Red label",
"precio": "100",
"categoriaid": "2",
"url": "false"
}
]
}
}
and this is my code but it breaks the app any ideas on how can i make change my code in order to make it fill the tableview with its correspondent section and rows in each sections
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:self.menuInfo options:NSJSONReadingMutableContainers error:nil];
NSDictionary *cat = [json objectForKey:#"Categories"];
for(NSString *categories in cat){
Categorias *categorias = [[Categorias alloc]initWithNombre:categories];
NSDictionary *listTagDict = [cat objectForKey:categories];
for (NSString *prod in listTagDict) {
NSArray *rows = [listTagDict objectForKey:prod];
for (NSDictionary *rowDict in rows) {
NSString* pID = [rowDict objectForKey:#"id"];
NSString* pNombre = [rowDict objectForKey:#"nombre"];
NSString* pPrecio = [rowDict objectForKey:#"precio"];
NSString* pUrl = [rowDict objectForKey:#"url"];
Productos* productos = [[Productos alloc]initWithNombre:pNombre productoID:pID precio:pPrecio iconUrl:pUrl];
[categorias addRow:productos];
}
}
}
here are my two object clases the .m part
#implementation Productos
-(id)initWithNombre:(NSString *)name productoID:(NSString *)pId precio:(NSString*)prec iconUrl:(NSString*)url{
self = [super init];
if (self) {
self.nombre = name;
self.productoID = pId;
self.precio = prec;
self.iconUrl = url;
}
return self;
}
#end
#interface Categorias(){
NSMutableArray *rows;
}
#end
#implementation Categorias
-(id)initWithNombre:(NSString *)name{
self = [super init];
if (self) {
self.nombre = name;
}
return self;
}
-(void)addRow:(Productos *)row {
[rows addObject: row];
}
-(NSArray *)rowData {
return [NSArray arrayWithArray: rows];
}
#end
you are parsing the json response in wrong way,
try this,
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:self.menuInfo options:NSJSONReadingMutableContainers error:nil];
NSDictionary *cat = [json objectForKey:#"Categories"];
NSMutableArray *categoryArray = [NSMutableArray new];
for(NSString *key in [cat allKeys]){
Categorias *category = [[Categorias alloc]initWithNombre:key];
NSArray *listTagDict = [cat objectForKey:key];
for (NSDictionary *prod in listTagDict) {
NSString* pID = [prod objectForKey:#"id"];
NSString* pNombre = [prod objectForKey:#"nombre"];
NSString* pPrecio = [prod objectForKey:#"precio"];
NSString* pUrl = [prod objectForKey:#"url"];
Productos* productos = [[Productos alloc]initWithNombre:pNombre productoID:pID precio:pPrecio iconUrl:pUrl];
[category addRow:productos];
}
[categoryArray addObject:category];
}
use categoryArray to populate tableview.
in this, categoryArray count will be section count, and each section contains rows with rowData array of each category.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [categoryArray count];
}
-(NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
Category *category = [categoryArray objectAtIndex:section];
return category.nombre;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
Category *category = [categoryArray objectAtIndex:section];
NSArray *rows = [category rowData];
return [rows count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath]; return cell;
Category *category = [categoryArray objectAtIndex:indexPath.section];
NSArray *rows = [category rowData];
Product *product = [rows objectAtIndex:indexPath.row];
//populate cell with product
}
I need to display the address in a tableview. How can i break the JSON and save the addresses in an NSArray.
The JSON is :
{
"Rank": 54,
"data": [
{
"number": 1,
"address": "x mandt "
},
{
"number": 2,
"address": "x mandt2 "
}
]
}
COde is:
NSDictionary *dic = (NSDictionary *) responseObject;
NSDictionary * dat = [dic objectForKey:#"data"];
NSArray *add =[dat objectForKey:#"address"];
The above code, doesn't retrieve and save all the address in the add array. How can i solve this?
assume that this is your serialization data
NSDictionary *jsonArray = [NSJSONSerialization JSONObjectWithData:responseData options: NSJSONReadingMutableContainers error: &err];
// here I start your work
NSArray *infoDict=[jsonArray objectForKey:#"data"];
for (NSDictionary *tmp in infoDict)
{
NSMutableDictionary *temparr=[[NSMutableDictionary alloc]init];
[temparr setValue:[tmp objectForKey:#"number"] forKey:#"number"];
[temparr setValue:[tmp objectForKey:#"address"] forKey:#"address"];
[_tdataSource addObject:temparr];
}
[yourtableviewNAme reloadData];
here I add the Tableview DataSource and delegate method
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section
{
return [self.tdataSource count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"resultCell";
yourtableviewCellName *cell = [self.yourtableName dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[yourtableviewCellName alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] ;
}
cell.textLabel.text=[[self.tdataSource objectAtIndex:indexPath.row]objectForKey:#"address"];
return cell;
}
I think you better just use the literal syntax for retrieving this. The way you retrieve is just fine. You probably just add some introspection:
NSDictionary *responseDict = (NSDictionary *) responseObject;
if (responseDict.count) {
NSArray *dataArray = responseDict[#"data"];
if (dataArray.count) {
// do whatever you want
}
}
You made a mistake when you retrieve the key word data, you will get an array after that but not a NSDictionary.
It should be:
NSArray *add =[dic objectForKey:#"data"];
Then if you want to have the address (I am considering address in 0'th index) then do this:
NSString *str = [[add objectAtIndex: 0] objectForKey:#"address"];
Edit:
Declare a class variable like:
#interface YourClassName (){
NSMutableArray *dataSource;
}
Populate the dataSource like:
dataSource =[dic objectForKey:#"data"];
Then In your cellForRowAtIndexPath method do this:
cell.textLabel.text = [[dataSource objectAtIndex:indexPath.row] objectForKey:#"address"];
I am considering you have single section in your tableview. Hope this helps.. :)
I'm trying to parse a JSON file containing urls to images.
My code:
NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:#"http://my-site/pictureparse.php?name=Name"]];
NSData *data= [NSData dataWithContentsOfURL:URL];
if (data == nil) {
return;
}
NSError* error;
NSMutableDictionary *jsonIs = [NSJSONSerialization
JSONObjectWithData:data
options:kNilOptions
error:&error];
NSLog(#"Json : %#",jsonIs);
if (jsonIs != nil) {
NSString *item_media = [jsonIs objectForKey:#"link"];
where "link" is the link to the image in the JSON-file.
The JSON structure looks like this:
[
{
"link": "http://link-to-image.com/picture.jpg",
"title": "Title",
"published": "0:01 PM 24/10"
},
{
"link": "http://link-to-image.com/picture.jpg",
"title": "Title",
"published": "0:01 PM 24/10"
},
{
"link": "http://link-to-image.com/picture.jpg",
"title": "Title",
"published": "0:01 PM 24/10"
},
{
"link": "http://link-to-image.com/picture.jpg",
"title": "Title",
"published": "0:08 PM 23/10"
}
]
When I launch the app I see in NSLog that it parses the objects, but I get the error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFArray objectForKey:]: unrecognized selector sent to instance 0x16e81ed0
How can I take these parsed objects/links and display them in a feed, like Instagram?
I have tried with the following code, but it doesn't work...
#import "PicturesViewController.h"
#import "DemoViewController.h"
#import "SecondViewController.h"
#import "AppDelegate.h"
#import "RNBlurModalView.h"
#import "PictureJSON.h"
#import "HMSegmentedControl.h"
#interface PicturesViewController ()
{
NSInteger refreshIndex;
NSArray *images;
}
#end
#implementation PicturesViewController
- (void)viewDidLoad
{
HMSegmentedControl *segmentedControl = [[HMSegmentedControl alloc] initWithSectionTitles:#[#"Instagram", #"Hashtags", #"Facebook"]];
[segmentedControl setFrame:CGRectMake(10, 10, 300, 60)];
[segmentedControl addTarget:self action:#selector(segmentedControlChangedValue:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:segmentedControl];
[super viewDidLoad];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Menu" style:UIBarButtonItemStyleBordered target:self action:#selector(showMenu)];
UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(swipeHandler:)];
[self.view addGestureRecognizer:gestureRecognizer];
[self issueLoadRequest];
}
- (void)swipeHandler:(UIPanGestureRecognizer *)sender
{
[[self sideMenu] showFromPanGesture:sender];
}
- (void)segmentedControlChangedValue:(HMSegmentedControl *)segmentedControl1 {
[self issueLoadRequest];
}
- (void)segmentedControlSelectedIndexChanged:(id)sender
{
[self issueLoadRequest];
}
#pragma mark -
#pragma mark Button actions
- (void)showMenu
{
[[self sideMenu] show];
}
#pragma mark - Table view data source
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"PictureJSON";
PictureJSON *cell = (PictureJSON *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"PictureJSON" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
// The element in the array is going to be a dictionary. I JUST KNOW THIS. The key for the tweet is "text".
NSDictionary *tweet = [self.tweets objectAtIndex:indexPath.row];
NSLog(#"%#", [cell class]);
UIImageView *instaImage = [[UIImageView alloc] init];
instaImage.image = [tweet objectForKey:#"link"];
cell.titleLabel.text = [tweet objectForKey:#"title"];
cell.timeLabel.text = [tweet objectForKey:#"published"];
return cell;
}
- (void)issueLoadRequest
{
// Dispatch this block asynchronosly. The block gets JSON data from the specified URL and performs the proper selector when done.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://my-site.com/picutreparse.php?name=Name"]];
[self performSelectorOnMainThread:#selector(receiveData:) withObject:data waitUntilDone:YES];
});
}
- (void)receiveData:(NSData *)data {
// When we have the data, we serialize it into native cocoa objects. (The outermost element from twitter is
// going to be an array. I JUST KNOW THIS. Reload the tableview once we have the data.
self.tweets = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
[self.myTableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.tweets.count;
}
#end
I would really appreciate a solution!
The problem is that the object you get from your parsing is a NSArray and not a NSDictionary.
Edit your code to this one:
#interface PicturesViewController ()
{
// ...
NSArray *items;
}
At the point where you get the data:
items = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&error];
Finally:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// ...
NSDictionary *item = [items objectAtIndex:indexPath.row];
NSString *item_media = [item objectForKey:#"link"];
// ...
}
What is wrong you make NSMutableDictionary
NSMutableArray *jsonIs = [NSJSONSerialization
JSONObjectWithData:data
options:kNilOptions
error:&error];
NSLog(#"Json : %#",jsonIs);
if (jsonIs != nil) {
NSMutableDictionary* aDict = jsonIs[0];
NSString *item_media = [aDict objectForKey:#"link"];
}
your main JSON is an array because of "[...]" in this array you got dictionaries : "{..}"
edit for tableView question:
make the NSMutableArray *jsonIs to global
#implementation PicturesViewController{
NSMutableArray *jsonIs
}
then in tableview delegate:
NSString *item_media = [jsonIs[indexPath.row] objectForKey:#"link"];