JohnyFonno
JohnyFonno

Reputation: 31

How come my UITableView is repeating rows after 5 rows?

I have 7 rows in my database. I confirmed that all of the data is successfully coming over to the iOS side by NSLog the postArray which gives 7. However when I run my app, it will only display the first 5 rows, and then the first 2 rows instead of the 6th and 7th row from my database. Also when I NSLog the actual text from my 6th and 7th text view the correct text is in there... Why is it repeating after 5 rows? Thank you. Here is my code:

#import "DailyViewController.h"
#import "Post.h"

@interface DailyViewController ()

@end

@implementation DailyViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // View background
    [self.view setBackgroundColor:[UIColor colorWithRed:(255/255.0) green:(221/255.0) blue:(85/255.0) alpha:1.0f]];

    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://example.org/getPosts.php"]];
    NSData *data = [NSData dataWithContentsOfURL:url];

    jsonArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
    postArray = [[NSMutableArray alloc] init];

    for(int i = 0; i < jsonArray.count; i++)
    {
        NSString *nickname = [[jsonArray objectAtIndex:i] objectForKey:@"nickname"];
        NSString *squeal = [[jsonArray objectAtIndex:i] objectForKey:@"squeal"];

        [postArray addObject:[[Post alloc] initWithNickname:nickname andSqueal:squeal]];
    }

    viewArray = [[NSMutableArray alloc] init];
    for(int i = 0; i < postArray.count; i++)
    {
        Post *postObject;
        postObject = [postArray objectAtIndex:i];

        UILabel *nicknameLabel = [[UILabel alloc]initWithFrame:CGRectMake(30, 15, 320, 30)];
        nicknameLabel.text = postObject.nickname;
        nicknameLabel.font = [UIFont boldSystemFontOfSize:20];

        UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(25, 42, 320, 0)];
        textView.font = [UIFont systemFontOfSize:15];
        textView.text = postObject.squeal;
        textView.editable = false;
        [textView setScrollEnabled:false];
        [textView sizeToFit];
        [textView layoutIfNeeded];

         UIView *view = [[UIView alloc] initWithFrame: CGRectMake (0, 0, 320, 30+textView.frame.size.height)];

        [view addSubview:nicknameLabel];
        [view addSubview:textView];

        [viewArray addObject:view];
    }

    [self.tableView reloadData];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return postArray.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.contentView addSubview:[viewArray objectAtIndex:indexPath.row]];
    }

    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return 0;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UIView *view = [viewArray objectAtIndex:indexPath.row];
    return view.frame.size.height+30;
}

@end

Upvotes: 1

Views: 1021

Answers (3)

Mohannad A. Hassan
Mohannad A. Hassan

Reputation: 1648

UITableView reuses the cells with the same reuse identifier, which means that when you scroll so that a row is scrolled out of the visible area, it will be used to show new rows. That's why when your 1st and 2nd rows were scrolled out of the view, they were used to show the 5th and 6th row.

You need to modify how you load cells.

- (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];
        // Add and setup views here.
    }
    //Add content to view here
    // e.g. cell.textLabel.text = @"Some text";

    return cell;
}

BTW You can use the property textLabelof UITableViewCellinstead of creating a new label and adding it as as subview. If you need to have more control over your custom cell, then you should create a custom class and use a Storyboard file or a Xib file.

Upvotes: 1

picciano
picciano

Reputation: 22701

In your cellForRowAtIndexPath method, you are adding a subview to the cell's content view only if the cell is being initialized for the first time.

Rather, you should add/replace the subview on each call to cellForRowAtIndexPath.

Upvotes: 0

Ian MacDonald
Ian MacDonald

Reputation: 14010

if(cell == nil)
{
  cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
else
{
  [[cell.contentView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
}
[cell.contentView addSubview:[viewArray objectAtIndex:indexPath.row]];

Upvotes: 0

Related Questions