1

This is for a blog-type app, in which the blog post is shown and below you can read the several comments to that post.

| Post Title Here
|
| Post text here lorem ipsum 
| dolor bla bla bla
|
| ---------------------------------------------
| Comment 1
| ---------------------------------------------
| Comment 2
| ---------------------------------------------
| Comment 3
| ---------------------------------------------
| etc

My JSON feed looks like this:

...
{
    "post_id": "1463",
    "post_title": null,
    "post_text": "dffsdjdflkjklk dlfkjsdlfkj",
    "comment": [
        {
            "comment_id": "2162",
            "comment_text": "yuiyuiiopiop",
        },
        {
            "comment_id": "2163",
            "comment_text": "tyutyutyutyuu",
        },
        {
            "comment_id": "2164",
            "comment_text": "sdfsertertr",
        },
    ]
},
...

And this is how I read it

NSDictionary *post           = self.detailItem;
NSArray      *commentThread  = [post objectForKey:@"comment"];
NSUInteger   commentCount    = [commentThread count];

    for (int i = 0; i < commentCount; i++) {
        NSDictionary *comment      = [commentThread objectAtIndex:i];
        NSString     *commentText  = [comment objectForKey:@"comment_text"];

        commentTextLabel.text  = commentText;
    }

In my storyboard I have one UILabel that is wired to commentTextLabel.

With the above approach only the last comment shows in my view. I expected the UILabel to be generated i times but that does not seem to be the case.

How should I do to get multiple UILabels created, one for each comment, so they end up stacked as I show in the top of this post?

Any kind of help, pointers or advice is greatly appreciated.

pepe
  • 9,799
  • 25
  • 110
  • 188

2 Answers2

2

Since you have one UILabel hooked up in your storyboard, you are overwriting it's content in every iteration.

What you want to do is to create a new UILabel for each comment, set it's frame and add it as a subview to it's parent view and iterate to the next.

For example:

for (int i = 0; i < commentCount; i++) {
    NSDictionary *comment      = [commentThread objectAtIndex:i];
    NSString     *commentText  = [comment objectForKey:@"comment_text"];
    UILabel      *newLabel     = [UILabel alloc] init];

    newLabel.text = commentText;
    newLabel.frame = CGRectMake(origin.x, origin.y, width, height);
    [self.view addSubview:newLabel];
}

origin.x, origin.y would have to be calculated each time to fit your needs, you could insert a variable to hold the last origin.y and add it's height and a margin each time to make it look like a list.

On the other hand, the most efficient way to do this would be to use a UITableView. Your JSON could be parsed into an array and each entry would be a cell. This way you take advantage of reusing cells. If you do not reuse cells and keep going with your current setup, your app's performance could be affected if you have too many comments.

Also take into consideration that presenting labels in a TableView or ScrollView isn't very effective framerate-wise. The alpha-blending will cut into your performance. I suggest you also google about tweetie's fast performing tableviews or check this post atebits Twitter fast scrolling

Community
  • 1
  • 1
  • thanks @jose that's very helpful - would the UITable resize its height if a specific comment is longer than others? or will all cells be of the same height? – pepe Oct 16 '12 at 01:27
  • @torr to achieve that you would have to calculate the size of the text with the method: - (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(NSLineBreakMode)lineBreakMode inside the UITableView's protocol - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath You check the indexPath.row to see which cell is being calculated, access your object through the dataSource using that row, then use the sizeWithFont method and return the calculated height. – Jose Ventura Oct 16 '12 at 01:34
  • would it be possible to iterate as you described but instead of iterating programmatically created elements, iterate through elements created in Interface Builder? – pepe Oct 16 '12 at 23:33
1

You should probably replace the UILabel with an UITableViewController. That way you could pass the commentThread array directly to the UITableViewController (via a custom property that you would create). The UITableViewController would then be able to iterate over the array via its datasource methods (that you would have to implement).

As you currently have it, you are not creating a new label for each iteration of the loop. All you are doing is setting the text of the 1 label that you wired up. If you really really want to use labels, then wire up a UIView that will be a container for your labels, and then, in your for loop create the labels and add them to that UIView that you created in you storyboard.

my two cents :)

haroldcampbell
  • 1,512
  • 1
  • 14
  • 22
  • thanks harold - the last part of what you said `and add them to that UIView...` -- how would that look like in code? – pepe Oct 16 '12 at 00:37
  • do you mean replacing UILable with a UITableView? I cannot drop a UITableViewController inside my DetailView... but I can drop a UITableView then a UITableViewCell – pepe Oct 17 '12 at 00:45