I am parsing JSON and storing it in an array.I have a custom cell subclass in which I am trying to set the title of a label from the content of parsed JSON.
This is the parsing process.
#implementation BlogScreenViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.jsonArray = [[NSMutableArray alloc]init];
NSError *error = nil;
NSURL *url = [NSURL URLWithString:#"http:web_services/blog.php"];
NSData *data = [NSData dataWithContentsOfURL:url];
self.jsonArray = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
for (NSDictionary *obj in self.jsonArray)
{
NSLog(#"JSON string output :- %# ", [obj objectForKey:#"titre"]); // shows titles
}
In custom cell subclass
// set blog title label
UILabel *blogTitleLabel = [[UILabel alloc]initWithFrame:CGRectMake(60, 20, 200, 20)];
// blogTitleLabel.text = #"This is blog title"; // This shows properly if used.
for (NSDictionary *obj in blogScreenVC.jsonArray ) //This doesn't work.
{
blogTitleLabel.text = [NSString stringWithFormat:#"%#",[obj objectForKey:#"titre"]];
}
[blogTitleLabel setFont:[UIFont systemFontOfSize:9]];
[self addSubview:blogTitleLabel];
Instead of Setting lebel.text in customcell class add it in the cellForRowAtIndexPath.
Create Property of label in customcell.h file
#property (nonatomic, weak) IBOutlet UILabel *label;
And in customcell.m file synthesys it.
#synthesize label = _label;
And in you viewcontroller.m file
#import "CustomCell.h"
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"CustomCell";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
if (self.jsonArray.count !=0) {
NSMutableDictionary * tmpDictn = [self.jsonArray objectAtIndex:indexPath.row];
if ([tmpDictn objectForKey:#"titre"] != nil)
{
cell.label.text = [tmpDictn objectForKey:#"titre"];
}else{
cell.label.text = #"tmpDictn does not contain data";
}
}else{
cell.label.text = #"jsonArray does not contain data";
}
return cell;
}
Related
I've got a Table View Cell in .xib. I've got a UILabel and UIImageView in the .xib.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
{
SchoolsTableViewCell *cell = (SchoolsTableViewCell *) [[[NSBundle mainBundle] loadNibNamed:#"SchoolsTableViewCell" owner:self options:nil] lastObject];
NSLog(#"Before: %#", cell.nameLabel.text);
cell.nameLabel.text = [NSString stringWithFormat:#"Name: %#", [object objectForKey:#"name"]];
NSLog(#"After: %#", cell.nameLabel.text);
PFFile *file = [object objectForKey:#"logo"];
[file getDataInBackgroundWithBlock:^(NSData *data, NSError *error)
{
cell.logoImageView.image = [UIImage imageWithData:data];
}];
return cell;
}
As you can see, I have 2 NSLog()s, printing the below:
2015-07-08 20:17:26.739 o [1871:108786] Before: (null)
2015-07-08 20:17:26.740 o [1871:108786] After: Name: SMSAS
That is expected.
However, on my Simulator, I can only see a blank cell with Name:. It should show SMSAS in the label, and load a logo, but it's not happening. I can pass the object to the next View Controller when the cell is tapped, and it can show in that View Controller.
This is my .m for the cell.
#implementation SchoolsTableViewCell
- (void)awakeFromNib
{
[super awakeFromNib];
self.nameLabel = [[UILabel alloc] init];
self.logoImageView = [[UIImageView alloc] init];
[self.contentView addSubview:self.nameLabel];
[self.contentView addSubview:self.logoImageView];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
}
#end
I'm sure it's a simple mistake. Anyone care to open my eyes? Thanks!
Use dequeueReusableCellWithIdentifier
static NSString * CellIdentifier = #"SchoolsTableViewCell";
SchoolsTableViewCell *cell = (SchoolsTableViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SchoolsTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
Hi everyone I would like to ask I want to show JSON data and customize the position for image and text in Table View.
how can I do like that? please advice me.
You can take a look at the Image Url.
for image 1 it is the result as I've parsing from JSON.
Image 1
for image 2 it is my goal.
Image 2
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDataSource,UITableViewDelegate>
#property (retain, nonatomic) IBOutlet UITableView *myTableView;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
{
NSMutableArray *myObject;
// A dictionary object
NSDictionary *dict;
// Define keys
NSString *galleryid;
NSString *name;
NSString *titlename;
NSString *thumbnail;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Define keys
galleryid = #"GalleryID";
name = #"Name";
titlename = #"TitleName";
thumbnail = #"Thumbnail";
// Create array to hold dictionaries
myObject = [[NSMutableArray alloc] init];
NSData *jsonData = [NSData dataWithContentsOfURL:
[NSURL URLWithString:#"MY_JSON_URL"]];
id jsonObjects = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
// values in foreach loop
for (NSDictionary *dataDict in jsonObjects) {
NSString *strGalleryID = [dataDict objectForKey:#"GalleryID"];
NSString *strName = [dataDict objectForKey:#"Name"];
NSString *strTitleName = [dataDict objectForKey:#"TitleName"];
NSString *strThumbnail = [dataDict objectForKey:#"Thumbnail"];
dict = [NSDictionary dictionaryWithObjectsAndKeys:
strGalleryID, galleryid,
strName, name,
strTitleName, titlename,
strThumbnail, thumbnail,
nil];
[myObject addObject:dict];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return myObject.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
// Use the default cell style.
cell = [[[UITableViewCell alloc] initWithStyle : UITableViewCellStyleSubtitle
reuseIdentifier : CellIdentifier] autorelease];
}
NSDictionary *tmpDict = [myObject objectAtIndex:indexPath.row];
NSURL *url = [NSURL URLWithString:[tmpDict objectForKey:thumbnail]];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[UIImage alloc] initWithData:data];
cell.imageView.image = img;
cell.textLabel.text = [tmpDict objectForKey:name];
cell.detailTextLabel.text= [tmpDict objectForKey:titlename];
//[tmpDict objectForKey:memberid]
//[tmpDict objectForKey:name]
//[tmpDict objectForKey:titlename]
//[tmpDict objectForKey:thumbnail]
return cell;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)dealloc {
[_myTableView release];
[super dealloc];
}
#end
It will be easy if creating custom TableviewCell (subclass to UITableViewCell) to display the array of objects you have, than using UITableViewCell to display as you desired.
Create custom UITableviewCell with xib or with storyboard and create properties as you needed and give the position and styling for the cell elements.
Bind data for the cells in your cellForRowAtIndexPath method.
For more information, refer: this and this for more info
-(void)viewDidLoad {
[super viewDidLoad]; // Do any additional setup after loading the view from its nib. self.navigationItem.title = #"New Arrivals";
[super viewDidLoad]; idsArray=[[NSMutableArray alloc]init]; namesArray=[[NSMutableArray alloc]init]; imagesArray=[[NSMutableArray alloc]init];
// create the URL we'd like to query
NSURL *myURL = [[NSURL alloc]initWithString:#"http://www.bikrionline.com/nwarvl-json.php"];
// we'll receive raw data so we'll create an NSData Object with it NSData *myData = [[NSData alloc]initWithContentsOfURL:myURL];
// now we'll parse our data using NSJSONSerialization if ([myData length]>0) { id myJSON = [NSJSONSerialization JSONObjectWithData:myData options:NSJSONReadingMutableContainers error:nil]; NSArray *jsonArray = (NSArray *)myJSON; for (int i=0 ; i<[jsonArray count] ; i++) { NSMutableString *urlString = [[NSMutableString alloc]initWithString:#"http://www.bikrionline.com/products/zmphotos/"]; NSString * name = [[[jsonArray objectAtIndex:i]objectForKey:#"prodname"]retain]; [namesArray addObject:name]; [idsArray addObject:[[jsonArray objectAtIndex:i]objectForKey:#"prodid"]]; [urlString appendString:[[jsonArray objectAtIndex:i]objectForKey:#"imageurl"]]; UIImage *imageObj = [self getImageFromUrl:urlString]; urlString = nil; [imagesArray addObject:imageObj]; } }
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
CustomCellView *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *arrNib = [[NSBundle mainBundle] loadNibNamed:#"CustomCellView" owner:self options:nil];
cell = [arrNib objectAtIndex:0];
}
cell.imgName.text = [namesArray objectAtIndex:indexPath.row];
cell.custImageView.image=[imagesArray objectAtIndex:indexPath.row];
return cell;
}
You can use some Lib like SDWebImage or Afnetworking. Libs support lazy load image and auto cache this image.
All you need to do:
[cell.imageView setImageWithURL:[NSURL URLWithString:#"url of image"]
placeholderImage:nil];
This is looking a similar question like lazy loading of an image: Check iOS lazy-loading of table images and Loading images on scrollview using lazy loading
for your answer
I have 3 custom table cells in my UITableView. The first two cells have set positions followed by a random number of cells.
For my row count I use :
return [stepLabel count] +2;
And for my tablecells I use :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *stepsCellIdentifier = #"StepsViewCell";
static NSString *descIdentfier = #"descViewCell";
static NSString *videoCellIdentfier = #"videoViewCell";
if( indexPath.row == 0 ) {
UITableViewCell *cell = nil;
cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:videoCellIdentfier];
if( !cell ) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"videoViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.textLabel.text = [descLabel objectAtIndex:indexPath.row];
return cell;
}
else if( indexPath.row == 1 ) {
stepDescCell *cell = nil;
cell = (stepDescCell *)[tableView dequeueReusableCellWithIdentifier:descIdentfier];
if( !cell ) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"descViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.descTextLabel.text = [descLabel objectAtIndex:indexPath.row - 1];
return cell;
}
else {
StepViewCell *cell = nil;
cell = (StepViewCell *)[tableView dequeueReusableCellWithIdentifier:stepsCellIdentifier];
if( !cell ) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"StepsViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.stepTextLbl.text = [stepLabel objectAtIndex:(indexPath.row - 2)];
NSString *imageThumb = [thumbImg objectAtIndex:(indexPath.row - 2)];
[cell.thumbImage setImage:[UIImage imageNamed: imageThumb] forState:UIControlStateNormal];
return cell;
}
}
All this works perfectly, however when I try to send a string from the table across a segue to another UIViewController I get the following error:
index (-2 (or possibly larger)) beyond bounds (3)'
The prepare for segue method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"imageBigShow"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
imageBigViewController *destViewController = segue.destinationViewController;
NSString *largeImgString = [largeImg objectAtIndex:(indexPath.row - 2)];
destViewController.imageBigString = largeImgString;
}
}
What am I doing wrong?
UPDATE
#implementation detailViewController
{
NSArray *thumbImg;
NSArray *stepLabel;
NSArray *descLabel;
NSArray *largeImg;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Find out the path of recipes.plist
NSDictionary *mapping = #{
#"How to wear a Kilt" : #"wearAKilt",
#"How to tie a cravat" : #"wearACravat",
#"How to wear a sporran" : #"wearASporran",
#"How to tie Ghillie Brogues" : #"wearTheShoes",
#"How to wear the accessories" : #"wearAccessories",
#"How to tie a cravat" : #"wearACravat",
#"How to Measure the Neck" : #"htmNeck",
#"How to Measure the chest" : #"htmChest",
#"How to Measure the waist" : #"htmWaist",
};
NSString *name = [mapping objectForKey:self.title];
NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:#"plist"];
// Load the file content and read the data into arrays
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
thumbImg = [dict objectForKey:#"thumbImg"];
stepLabel = [dict objectForKey:#"stepLabel"];
descLabel = [dict objectForKey:#"descLabel"];
largeImg = [dict objectForKey:#"largeImg"];
}
You have the following line:
NSString *largeImgString = [largeImg objectAtIndex:(indexPath.row - 2)];
If the user taps on the 1st or 2nd rows (index paths with row 0 or 1), this code will fail.
Everything works but can't assign value to the UILable of custom cell of searchResultsTableView. I am using the same custom UITableViewCell for my table view controller and it's searchDisplayController. I am using storyboard for the table view controller and table view cell. As you can see in the code, if I NSLog the value of self.searchResults[indexPath.row][#"name"], I can see the result in the console, but if I assign this value to cell.name.text, it won't work, but in the table view controller, it's working. The cell's imageView is working, I just can't assign any value to the cell's UILabel.
- (void)viewDidLoad
{
[super viewDidLoad];
[self.searchDisplayController.searchResultsTableView registerClass:[LocalCell class] forCellReuseIdentifier:#"Cell2"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
static NSString *CellIdentifier2 = #"Cell2";
if (tableView == self.searchDisplayController.searchResultsTableView) {
LocalCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2 forIndexPath:indexPath];
if (!cell) {
cell = [[LocalCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier2];
}
cell.name.text = self.searchResults[indexPath.row][#"name"];
NSLog(#"%#", self.searchResults[indexPath.row][#"name"]); // has value
NSLog(#"%#", cell.name.text); // null
return cell;
} else
{
LocalCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (!cell) {
cell = [[LocalCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.name.text = self.restaurants[indexPath.row][#"name"];
return cell;
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 80;
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
float radius = 1000.0f;
NSString *searchContent = [searchBar.text stringByReplacingOccurrencesOfString:#" " withString:#"%20"];
if ([searchContent length] > 0) {
NSString *urlString = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=%f,%f&radius=%f&types=food&key=%#&sensor=true&name=%#", [[[NSUserDefaults standardUserDefaults] objectForKey:#"lat"] floatValue], [[[NSUserDefaults standardUserDefaults] objectForKey:#"lon"] floatValue], radius, AppKey, searchContent];
__weak LocalViewController *weakSelf = self;
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
NSURLSessionDataTask *taks = [session dataTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error) {
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
weakSelf.nextPageToken = dict[#"next_page_token"];
weakSelf.searchResults = dict[#"results"];
NSLog(#"search results: %#", weakSelf.searchResults);
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.searchDisplayController.searchResultsTableView reloadData];
});
}
}];
[taks resume];
}
}
LocalCell.h
#import <UIKit/UIKit.h>
#interface LocalCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UILabel *name;
#property (weak, nonatomic) IBOutlet UIImageView *imageView;
#property (weak, nonatomic) IBOutlet UILabel *desc;
#property (weak, nonatomic) IBOutlet UILabel *distance;
#end
I looked in your project:
NSLog(#"%#", cell.name.text); // null
Because cell.name is nil.
The explanation is: then you load your normal tableView, the cell "LocalCell" is loading from Storyboard, allocating and initialising your labels, but then you using self.searchDisplayController.searchResultsTableView you initialise "LoadCell", but never initialise his labels (because they are weak IBOutlets - and used in storyboard).
To solve your problem, I found 3 solutions:
1. Create another SearchCell with strong references to his UILabels, initialise all UILabel s in -(id)init of SearchCell. Then use it in your controller.
[self.searchDisplayController.searchResultsTableView registerClass:[SearchCell class] forCellReuseIdentifier:#"SearchCell"];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
static NSString *SearchCellIdentifier = #"SearchCell";
Restaurant *res;
if (tableView == self.searchDisplayController.searchResultsTableView)
{
SearchCell *cell = [tableView dequeueReusableCellWithIdentifier:SearchCellIdentifier forIndexPath:indexPath];
if (!cell) {
cell = [[SearchCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
res = (Restaurant *)self.searchResults[indexPath.row];
cell.nameLabel.text = res.name;
cell.descLabel.text = res.desc;
// image load
return cell;
}
else
{
LocalCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (!cell) {
cell = [[LocalCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
res = (Restaurant *)self.restaurants[indexPath.row];
cell.nameLabel.text = res.name;
cell.descLabel.text = res.desc;
// image load
return cell;
}
}
Another way is to create a nib with your cell "SearchCellNib", and use your created LoadCell class. For load nib use:
cell = (LoadCell*)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = (LoadCell*)[[[NSBundle mainBundle] loadNibNamed:#"SearchCellNib" owner:nil options:nil] objectAtIndex:0];
}
Or use UITableViewCell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SearchCellIdentifier forIndexPath:indexPath];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
res = (Restaurant *)self.searchResults[indexPath.row];
cell.textLabel.text = res.name;
cell.detailTextLabel.text = res.desc;