Ruslanas Kudriavcevas
Ruslanas Kudriavcevas

Reputation: 89

UITableView inside static cell

i have a problem when put UITableView inside static cell of another UITableView in UITableViewController. If self.skillsTableView has more cells than self.tableView my app crashes with exeption:

* Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayI objectAtIndex:]: index 6 beyond bounds [0 .. 5]'

Here is my code:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *skillsCellIdentifier = @"skill_cell";
    if (tableView == self.skillsTableView) {
        NSLog(@"GET DYNAMIC %li", [tableView numberOfRowsInSection:0]);
        ServicesTableViewCell *cell = (ServicesTableViewCell*)[tableView dequeueReusableCellWithIdentifier:skillsCellIdentifier forIndexPath:indexPath];
        Services *skill = [self.servicesArray objectAtIndex:indexPath.row];
        cell.titleLabel.text = skill.title;
        cell.priceLabel.text = skill.price;
        return cell;
    }
    else {
        NSLog(@"GET STATIC %li", [super tableView:tableView numberOfRowsInSection:0]);
        return [super tableView:tableView cellForRowAtIndexPath:indexPath];
    }
}

and:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (tableView == self.skillsTableView) {
        NSLog(@"DYNAMIC -- %li", self.servicesArray.count);
        return self.servicesArray.count;
    }
    else {
        NSLog(@"Static == %li", [super tableView:tableView numberOfRowsInSection:section]);
        return [super tableView:tableView numberOfRowsInSection:section];
    }
}

Output:

2014-05-28 09:19:55.461 SesApp[32289:60b] Static == 6
2014-05-28 09:19:55.461 SesApp[32289:60b] GET STATIC 6
2014-05-28 09:19:55.463 SesApp[32289:60b] GET STATIC 6
2014-05-28 09:19:55.464 SesApp[32289:60b] GET STATIC 6
2014-05-28 09:19:55.465 SesApp[32289:60b] GET STATIC 6
2014-05-28 09:19:55.466 SesApp[32289:60b] GET STATIC 6
2014-05-28 09:19:55.470 SesApp[32289:60b] DYNAMIC -- 0
2014-05-28 09:19:55.610 SesApp[32289:60b] Static == 6
2014-05-28 09:19:55.611 SesApp[32289:60b] DYNAMIC -- 7
2014-05-28 09:19:55.612 SesApp[32289:60b] GET STATIC 6
2014-05-28 09:19:55.613 SesApp[32289:60b] GET DYNAMIC 7
2014-05-28 09:19:55.617 SesApp[32289:60b] GET DYNAMIC 7
2014-05-28 09:19:55.619 SesApp[32289:60b] GET DYNAMIC 7
2014-05-28 09:19:55.621 SesApp[32289:60b] GET DYNAMIC 7
2014-05-28 09:19:55.623 SesApp[32289:60b] GET DYNAMIC 7
2014-05-28 09:19:55.625 SesApp[32289:60b] GET DYNAMIC 7
2014-05-28 09:19:55.627 SesApp[32289:60b] GET DYNAMIC 7
2014-05-28 09:23:08.897 SesApp[32289:60b] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 6 beyond bounds [0 .. 5]'

Upvotes: 1

Views: 939

Answers (3)

Rikesh Subedi
Rikesh Subedi

Reputation: 1845

I was also facing similar issue. When I checked the stack trace, it says there's issue in following method, which was throwing 'NSRangeException'

tableView(_ tableView: UITableView, indentationLevelForRowAt indexPath: IndexPath)

I did override the method to always return 0

override func tableView(_ tableView: UITableView, indentationLevelForRowAt indexPath: IndexPath) -> Int {
        return 0
}

It's working now.

Upvotes: 0

Ruslanas Kudriavcevas
Ruslanas Kudriavcevas

Reputation: 89

I don't know why in my case this happens, but if someone in the future will face the same problem, i solve my issue in this way:

I add UIContainerView inside static cell, in UIContainerView i have UITableViewController with this code:

InsideTableViewController.h

@protocol InsideTableDelegate
- (void)insideTableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath;
@end

@interface InsideTableViewController : UITableViewController

@property (nonatomic, assign) id <InsideTableDelegate> delegate;
@property (nonatomic, strong) NSNumber *count;

@end

InsideTableViewController.m

#import "InsideTableViewController.h"

@interface InsideTableViewController ()

@end

@implementation InsideTableViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
}

#pragma mark - Table view data source

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

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [self.count intValue];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellIdentifier = @"InsideCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
    cell.textLabel.text = [NSString stringWithFormat:@"Inside Cell %li", indexPath.row];
    return cell;
}

#pragma mark - TableView Delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [self.delegate insideTableView:tableView didSelectRowAtIndexPath:indexPath];
}

#pragma mark - Setter

- (void)setCount:(NSNumber *)count {
    _count = count;
    [self.tableView reloadData];
}

@end

And in my UITableViewController with static cells:

CustomTableViewController.m

#import "CustomTableViewController.h"
#import "InsideTableViewController.h"

@interface CustomTableViewController () <InsideTableDelegate> {
    int insideCellsCount;
}
@property (weak, nonatomic) IBOutlet UIView *insideTableViewContainer;
@property (nonatomic, strong) InsideTableViewController *insideTableViewController;
@end

@implementation CustomTableViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    insideCellsCount = 1;
    self.insideTableViewController.count = [NSNumber numberWithInt:insideCellsCount];
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"InsideTable"]) {
        self.insideTableViewController = [segue destinationViewController];
        self.insideTableViewController.delegate = self;
    }
}

#pragma mark - TableView DataSource

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    switch (indexPath.row) {
        case 0:
            return insideCellsCount * 44;
            break;

        default:
            return 44;
            break;
    }
}

#pragma mark - TableView Delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    insideCellsCount++;
    self.insideTableViewController.count = [NSNumber numberWithInt:insideCellsCount];
    [tableView beginUpdates];
    [tableView endUpdates];
}

#pragma mark - InsideTableView Delegate

- (void)insideTableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    NSLog(@"INDEX: %li", indexPath.row);
}

@end

Upvotes: 0

Apurv
Apurv

Reputation: 17186

In both delegate methods, you should not call super method. You should put actual implementation over there.

i.e.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (tableView == self.skillsTableView) {
        return self.servicesArray.count;
    }
    else {
        return NUMBER_OF_ROWS_FOR_PARENT_TABLE_VIEW_FOR_THIS_SECTION;
    }
    return 0;
}

Same you need to do for cellForRowAtIndexPath method.

Upvotes: 2

Related Questions