Unable to show thumbnail left of Table Cell in iOS - objective-c

I have seen several posts on this here at SO but those solutions don't seem to work for me. Perhaps it's because I'm getting the image URL via JSON. All other text fields in JSON are coming through OK, it's just the image that I can't display and get a SIGABRT error.
The code in question is this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"PostCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSDictionary *post = [posts objectAtIndex:indexPath.row];
NSString *postText = [post objectForKey:#"post_text"];
NSString *postAuthorName = [post objectForKey:#"post_author_name"];
NSString *postPictureUrl = [post objectForKey:#"post_picture"];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:postPictureUrl]];
cell.textLabel.text = postText;
cell.detailTextLabel.text = [NSString stringWithFormat:#"by %#", postAuthorName];
cell.imageView.image = [UIImage imageWithData:data];
return cell;
}
My Table Cell is subtitle with no other changes or wiring.
Any idea where I'm messing up?
PS My full code using async request
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"PostCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSDictionary *post = [posts objectAtIndex:indexPath.row];
NSString *postText = [post objectForKey:#"post_text"];
NSString *postAuthorName = [post objectForKey:#"post_author_name"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSString *postpictureUrl = [post objectForKey:#"http://example.com/post/1200"];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:postpictureUrl]];
// NSLog(#"%#", data);
dispatch_async(dispatch_get_main_queue(), ^{
// [[cell imageView] setImage:[UIImage imageWithData:data]];
});
});
cell.textLabel.text = postText;
cell.detailTextLabel.text = [NSString stringWithFormat:#"by %#", postAuthorName];
return cell;
}

You can do this like in :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
[NSThread detachNewThreadSelector:#selector(downloadImages:) toTarget:self withObject: [NSMutableDictionary dictionaryWithObjectsAndKeys:imageURL,#"imageURL",[NSIndexPath indexPathWithIndex:indexPath.row],#"indexPath", nil]];
call above function and
- (void) downloadImages:(NSMutableDictionary*)dict{
NSURL *nurl = [NSURL URLWithString:[dict objectForKey:#"imageURL"]];
NSURLRequest *req = [NSURLRequest requestWithURL:nurl];
NSURLResponse * response;
NSData *data = [NSURLConnection sendSynchronousRequest: req returningResponse: &response error: &error];
UITableViewCell *cell = [YOURTABLENAME cellForRowAtIndexPath:(NSIndexPath*)[dict objectForKey:#"indexPath"]];
cell.imageView.image = [UIImage imageWithData:data];
if (error) {...handle the error}
}

A few minor changes and the below works (ie, thumbnail shows to the left of title and subtitle).
- (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];
}
NSDictionary *post = [posts objectAtIndex:indexPath.row];
cell.textLabel.text = [post objectForKey:#"post_text"];
cell.detailTextLabel.text = [post objectForKey:#"post_author_name"];
NSString *postpictureUrl = [post objectForKey:#"picture"];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:postpictureUrl]];
cell.imageView.image = [UIImage imageWithData:data];
return cell;
}
Note the use of initWithStyle:UITableViewCellStyleSubtitle instead of Default.
The guide here is an important read:
http://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/TableView_iPhone/TableViewCells/TableViewCells.html
Finally, note this is synchronous downloading of images which will not work in the real world.
So I'll be posting another question on SO about the best solution for this.

Related

How to make SDWebImage maintain size in UITableViewCell

cell.imageView is displayed correctly on first loading.
After the UITableViewCell move off screen and back on again, suddenly cell.imageView size has changed to fill the height of the cell.
Same thing when the cell set to highlighted state.
cell.imageView is created in interface builder.
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CustomCell";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
NSDictionary *dataType = [self.dataTypes objectAtIndex:indexPath.row];
[cell.imageView setImageWithURL:[NSURL URLWithString:[dataType valueForKey:#"imageURL"]]
placeholderImage:nil];
cell.titleLabel.text = [data valueForKey:#"name"];
cell.descriptionLabel.text = [data valueForKey:#"info"];
return cell;
}
try below answer and do needful changes in it
https://stackoverflow.com/a/15331306/1713478
in this answer add
cell.titleLabel.text = [data valueForKey:#"name"];
cell.descriptionLabel.text = [data valueForKey:#"info"];
and just change SimpleTableCell with CustomCell and in imageURL put your image URL
and do other needful changes.
may be your problem will solve.
Well inspired by Pratik's answer I decided to remove the UIImageView from interface builder and create it on the fly. This works as expected but I'm not sure why it's any different. Possibly something to do with the IB constraints.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CustomCell";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
NSDictionary *data = [self.dataTypes objectAtIndex:indexPath.row];
UIImageView *thumb = [[UIImageView alloc]initWithFrame:CGRectMake(11, 10, 52, 74)];
[thumb setImageWithURL:[NSURL URLWithString:[data valueForKey:#"imageURL"]]
placeholderImage:nil];
[cell addSubview:thumb];
[thumb release];
cell.titleLabel.text = [data valueForKey:#"name"];
cell.descriptionLabel.text = [data valueForKey:#"info"];
return cell;
}

Populating 2nd table in Objective C

I have two tables (Cell Identifier: Call and Cell Identifier: Cell2). I'm passing two arrays of Objects (one for each table) however when I go to do this in my tableView my 2nd table is bringing up the same data as my first table and not the data from the 2nd array. My arrays are set globally as NSMutableArray in my .h file. This is where I think the problem is within the code:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!cell)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// NSString *currDate = [[array objectAtIndex:indexPath.row] objectForKey:#"Current Date"]; //added
// NSString *someOtherKey = [[array objectAtIndex:indexPath.row] objectForKey:#"Some other key"]; //added
cell.textLabel.text = [array objectAtIndex:indexPath.row];
label1.text = [arrayDate1 objectAtIndex:indexPath.row];
label2.text = [arrayDate2 objectAtIndex:indexPath.row];
// cell.textLabel.text = [NSString stringWithFormat:#"%# %#", currDate, someOtherKey]; //added
return cell;
//This will Load the second table (myTableView2)
static NSString *CellIdentifier2 = #"Cell2";
UITableViewCell *cell2 = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if(!cell2)
{
cell2 = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier2];
}
// NSString *currDate = [[array objectAtIndex:indexPath.row] objectForKey:#"Current Date"]; //added
// NSString *someOtherKey = [[array objectAtIndex:indexPath.row] objectForKey:#"Some other key"]; //added
cell2.textLabel.text = [array2 objectAtIndex:indexPath.row];
return cell2;
}
It is indeed a problem in this function:
The code as written, will simply run until it gets to the first return cell; line and never run the code after that, therefore always returning an instance of a Cell cell.
In order to use two tables like this, you need to be able to tell them apart. Usually, you store both of them in a declared property. For the rest of this answer, I'll assume that you are doing that and that they are called table1 and table2.
Change you code to look like this:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([tableView isEqual:self.table1]) {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!cell)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// NSString *currDate = [[array objectAtIndex:indexPath.row] objectForKey:#"Current Date"]; //added
// NSString *someOtherKey = [[array objectAtIndex:indexPath.row] objectForKey:#"Some other key"]; //added
cell.textLabel.text = [array objectAtIndex:indexPath.row];
label1.text = [arrayDate1 objectAtIndex:indexPath.row];
label2.text = [arrayDate2 objectAtIndex:indexPath.row];
// cell.textLabel.text = [NSString stringWithFormat:#"%# %#", currDate, someOtherKey]; //added
return cell;
} else if ([tableView isEqual:self.table2]) {
//This will Load the second table (myTableView2)
static NSString *CellIdentifier2 = #"Cell2";
UITableViewCell *cell2 = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if(!cell2)
{
cell2 = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier2];
}
// NSString *currDate = [[array objectAtIndex:indexPath.row] objectForKey:#"Current Date"]; //added
// NSString *someOtherKey = [[array objectAtIndex:indexPath.row] objectForKey:#"Some other key"]; //added
cell2.textLabel.text = [array2 objectAtIndex:indexPath.row];
return cell2;
}
}
// If you reach this point, we don't recognize the table and return `nil`, then the program will crash. Handle this however you want.
return nil;

Custom cell not showing up in tableView

I have a custom cell with identifyer 'tweetCell' I have imported this into my tableviewcontroller.h file. I have linked the class to the prototype cell in storyboard. All the UILabels are wired up to the cell but I cannot get the tableview to display the custom cell. It did work? Then overnight stopped?!! I understand that class files need to start with an upper case letter, I have changed this but to no avail. Can anyone spot my error here? Thanks in advance......
- (void)fetchTweets
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData* data = [NSData dataWithContentsOfURL:
[NSURL URLWithString: #"http://search.twitter.com/search.json?q=%23mysearchhashtag"]];
NSError* error;
tweets = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
});
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return tweets.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"tweetCell";
customCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[customCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSDictionary *tweet = [tweets objectAtIndex:indexPath.row];
NSString *tweetText = [tweet valueForKey:#"text"];
NSArray *tweetComponents = [tweetText componentsSeparatedByString:#":"];
cell.firstDetail.text = [tweetComponents objectAtIndex:0];
cell.secondDetail.text = [tweetComponents objectAtIndex:1];
cell.thirdDetail.text = [tweetComponents objectAtIndex:2];
return cell;
}
Did you write this method - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView? Try like this.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}

Use of undeclared identifier 'cell'

i'm using a custom tablecell but i have a problem with parsing JSON in my uilabel i'm using the code below, this works great. To put something in my UILabel i simple do
cell.One.text = #"xx";
/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CustomCellIdentifier = #"CustomCellIdentifier ";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier: CustomCellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCell"
owner:self options:nil];
for (id oneObject in nib) if ([oneObject isKindOfClass:[CustomCell class]])
cell = (CustomCell *)oneObject;
}
return cell;
}
But when i try to parse something i normally do
- (void)fetchedData:(NSData *)responseData {
NSError* error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData //1
options:kNilOptions
error:&error];
NSArray* lastgame = [json objectForKey:#"items"];
NSDictionary* game = [lastgame objectAtIndex:0];
cell.One.text = [NSString stringWithFormat:#"%#",
[strijd objectForKey:#"One"]
];
}
But on this line i'm recieving an error: (Use of undeclared identifier 'cell') does anyone now how to fix thix?
cell.One.text = [NSString stringWithFormat:#"%#",
[strijd objectForKey:#"One"]
];
cell.One.text = [NSString stringWithFormat:#"%#",
[strijd objectForKey:#"One"]
];
your cell isn't declared in this methode, you have to do this in cellForRowAtIndexPath:
after you declare your cell with: CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier: CustomCellIdentifier];

Can't Get Data Loaded on First Row of UITableView

I'm trying to parse an HTML Data using HTMLParser (by Ben Reeves) and display results on UITableView. For some reasons I'm able to show up results only on last row of the tableView. Here's the code snippet:
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSData *responseData = [request responseData];
NSError *error = [request error];
HTMLParser *parser = [[HTMLParser alloc] initWithData:responseData error:&error];
HTMLNode *bodyNode = [parser body];
arrayNodes = [bodyNode findChildrenWithAttribute:#"class" matchingName:#"foo" allowPartial:NO];
for (HTMLNode *arrayNode in arrayNodes) {
NSString *footitle = [arrayNode allContents];
NSLog(#"%#", footitle);
fooLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 10, 200, 30)];
fooLabel.text = (#"%#", footitle);
fooLabel.textColor = [UIColor blackColor];
}
[self.fooTableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [arrayNodes count];
}
- (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];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}
// Configure the cell.
// [self.arrayNodes objectAtIndex:indexPath.row];
[cell.contentView addSubview:fooLabel];
return cell;
}
Where am I making the mistake?
for (HTMLNode *arrayNode in arrayNodes) {
NSString *footitle = [arrayNode allContents];
NSLog(#"%#", footitle);
fooLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 10, 200, 30)];
fooLabel.text = (#"%#", footitle);
fooLabel.textColor = [UIColor blackColor];
}
You are creating fooLabel's with same Frame size and location as many as arrayNodes array.
then in [cell.contentView addSubview:fooLabel]; it is showing you the last value that label is updated with.
take out that fooLabel from for loop.
in your cellForRowAtIndexPath:
HTMLNode* arrayNode = [arrayNodes objectAtIndex:[indexPath row]];
cell.textLabel.text = [NSString stringWithFormat:#"%#",[arrayNode allContents]];
You need to create the foolabel in your cellForRowAtindexPath method. Right now only one foolabel is created, and it is applied to each cell in turn and then set to the next cell, leaving it placed on the last cell. So instead you should do this:
-
(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];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}
// Configure the cell.
HTMLNode *arrayNode = [arrayNodes objectAtIndex:indexPath.row];
NSString *footitle = [arrayNode allContents];
UILabel *fooLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 10, 200, 30)];
fooLabel.text = (#"%#", footitle);
fooLabel.textColor = [UIColor blackColor];
[cell.contentView addSubview:fooLabel];
[fooLabel release];
return cell;
}