简体   繁体   中英

UITableView Inside UITableViewCell Issues

My set up here is that I have a UITableView with static cells defined in a storyboard. In one of static cells, I have a nested UITableView that is dynamic and has its content populated programmatically. I have researched this and assume this to be a perfectly valid configuration, as you are allowed to have any kind of UIView subclass (ie, a table view) inside a UITableViewCell .

However, whenever the view is loaded, I get an index beyond bounds exception, even though my backing data structure is valid and I've assured all the inner table view's delegate methods return the correct values. I have placed breakpoints in my cellForRowAtIndexPath: method, but that is fruitless, as the exception is thrown in between calls to that method. So I'm not sure what I am doing wrong or if secretly this is an invalid configuration.

The goal of this interface is to show an invoice and all its associated line items (the nested/embedded table view) on the same screen, versus the way I had it before where you would tap to view the line items on a separate UITableViewController view.

See my screenshot and code below.

表格视图布局的屏幕截图

    #pragma mark - Table view data source

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        NSInteger count = 0;

        if (tableView == self.tableView) {
            count = [super numberOfSectionsInTableView:tableView];
        } else if (tableView == itemsTable) {
            count = 3;
        }

        return count;
    }

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        NSInteger count = 0;

        if (tableView == self.tableView) {
            count = [super tableView:tableView numberOfRowsInSection:section];
        } else if (tableView == itemsTable) {
            switch (section) {
                case 0:
                    // Header
                    count = 1;
                    break;
                case 1:
                    // Items
                    count = assoicatedInvoice.items.count;
                    break;
                case 2:
                    // Add item
                    count = 1;
                    break;
                default:
                    break;
            }
        }

        return count;
    }

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        UITableViewCell * cell;

        if (tableView == self.tableView) {
            cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
        } else if (tableView == itemsTable) {
            InvoiceDetailEmbeddedLineItemViewCell * iCell;

            switch (indexPath.section) {
                case 0:
                    // Header section
                    iCell = (InvoiceDetailEmbeddedLineItemViewCell *) [tableView dequeueReusableCellWithIdentifier:invoiceDetailLineItemHeadersViewCellIdentifier];
                    break;

                case 1: {
                    // Item
                    InvoiceItem * associatedItem = [assoicatedInvoice.items objectAtIndex:indexPath.row];

                    iCell = (InvoiceDetailEmbeddedLineItemViewCell *) [tableView dequeueReusableCellWithIdentifier:invoiceDetailEmbeddedLineItemViewCellIdentifier];
                    iCell.nameLabel.text = associatedItem.name;
                    iCell.qtyLabel.text = [UtilityFunctions decimalFormatForInput:associatedItem.quantity minDecimalPlaces:0 maxDecimalPlaces:2];
                    iCell.priceLabel.text = [UtilityFunctions currencyFormatForInput:associatedItem.price];
                    iCell.taxLabel.text = [UtilityFunctions percentageFormatForInput:associatedItem.tax minDecimalPlaces:0 maxDecimalPlaces:2];
                    break;
                }

                case 2:
                    // Add new item
                    iCell = (InvoiceDetailEmbeddedLineItemViewCell *) [tableView dequeueReusableCellWithIdentifier:invoiceDetailLineItemAddItemCellIdentifier];
                    break;

                default:
                    break;
            }

            cell = iCell;
        }

        return cell;
    }

    - (NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
        NSString * title = nil;

        if (tableView == self.tableView) {
            if (section != 0) {
                title = [super tableView:tableView titleForHeaderInSection:section];
            } else {
                title = [Invoice friendlyNameForInvoiceType:assoicatedInvoice.invoiceType];
            }
        }

        return title;
    }

    - (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
        if (tableView == self.tableView) {
            return [super tableView:tableView viewForHeaderInSection:section];
        } else if (tableView == itemsTable) {
            return nil;
        }

        return nil;
    }

    - (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
        CGFloat height = 0.0;

        if (tableView == self.tableView) {
            if (indexPath.section != 1) {
                height = [super tableView:tableView heightForRowAtIndexPath:indexPath];
            } else {
                height = itemsTable.contentSize.height;
            }
        } else if (tableView == itemsTable) {
            height = 30.0;
        }

    //    height = [super tableView:tableView heightForRowAtIndexPath:indexPath];
        return height;
    }

After running, this is the stack trace I get.

    *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
    *** First throw call stack:
    (
        0   CoreFoundation                      0x041dc1e4 __exceptionPreprocess + 180
        1   libobjc.A.dylib                     0x0303a8e5 objc_exception_throw + 44
        2   CoreFoundation                      0x041908b2 -[__NSArrayI objectAtIndex:] + 210
        3   UIKit                               0x0244935f -[UITableViewDataSource tableView:indentationLevelForRowAtIndexPath:] + 127
        4   UIKit                               0x021c2f34 -[UITableViewController tableView:indentationLevelForRowAtIndexPath:] + 61
        5   UIKit                               0x01fe02cf __53-[UITableView _configureCellForDisplay:forIndexPath:]_block_invoke + 1786
        6   UIKit                               0x01f5481f +[UIView(Animation) performWithoutAnimation:] + 82
        7   UIKit                               0x01f54868 +[UIView(Animation) _performWithoutAnimation:] + 40
        8   UIKit                               0x01fdfbd0 -[UITableView _configureCellForDisplay:forIndexPath:] + 108
        9   UIKit                               0x01fe713d -[UITableView _createPreparedCellForGlobalRow:withIndexPath:] + 442
        10  UIKit                               0x01fe71f3 -[UITableView _createPreparedCellForGlobalRow:] + 69
        11  UIKit                               0x01fc8ece -[UITableView _updateVisibleCellsNow:] + 2428
        12  UIKit                               0x01fdd6a5 -[UITableView layoutSubviews] + 213
        13  UIKit                               0x01f5d964 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 355
        14  libobjc.A.dylib                     0x0304c82b -[NSObject performSelector:withObject:] + 70
        15  QuartzCore                          0x02f2345a -[CALayer layoutSublayers] + 148
        16  QuartzCore                          0x02f17244 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380
        17  QuartzCore                          0x02f170b0 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 26
        18  QuartzCore                          0x02e7d7fa _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 294
        19  QuartzCore                          0x02e7eb85 _ZN2CA11Transaction6commitEv + 393
        20  QuartzCore                          0x02f3c5b0 +[CATransaction flush] + 52
        21  UIKit                               0x01eec9bb _UIApplicationHandleEventQueue + 13095
        22  CoreFoundation                      0x0416577f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
        23  CoreFoundation                      0x0416510b __CFRunLoopDoSources0 + 235
        24  CoreFoundation                      0x041821ae __CFRunLoopRun + 910
        25  CoreFoundation                      0x041819d3 CFRunLoopRunSpecific + 467
        26  CoreFoundation                      0x041817eb CFRunLoopRunInMode + 123
        27  GraphicsServices                    0x044395ee GSEventRunModal + 192
        28  GraphicsServices                    0x0443942b GSEventRun + 104
        29  UIKit                               0x01eeef9b UIApplicationMain + 1225
        30  Field Manage                        0x000aae7d main + 141
        31  libdyld.dylib                       0x0355d701 start + 1
    )
    libc++abi.dylib: terminating with uncaught exception of type NSException

Kudos on an innovative way to put dynamic prototype cells in a static table :)

Static cell table views implement many of the size related methods (in this case indentationLevelForRowAtIndexPath ) and return values from internal arrays. Since you're trying to use the same delegate and dataSource for both tableviews, you're going to need to provide overrides for pretty much all of the delegate methods that have anything to do with sizing. A better solution might be to use a different data source and delegate entirely for the embedded table.

I do something like this in my app with nested UICollectionView s. I found the easiest way to make each CELL the dataSource and delegate for the table imbedded in it. So you'll have to make a total of 2 custom subclasses of UITableViewCell, set your static cell as an instance of the first subclass, then implement things like cellForRowAtIndexPath: in the .m for that first UITableViewCell subclass , and have it create and return an instance of the second subclass.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM