hazelvan
hazelvan

Reputation: 133

UITableView inside a UITableViewController

I'm getting a hard time using a UITableViewController with another UITableView. As we all know, a UITableViewController has its own UITableView. I used the UITableView to show details; each UITableViewCell has a corresponding field. So I named each cell by a unique Identifier. But then I need another UITableView that should include dynamic prototype cells, this UITableView's field is different from the premade UITableView, the number of rows depends on the array count. Here's my code:

@interface CourseJobTVC ()
{ sqlite3 *_db;}

@property (weak, nonatomic) IBOutlet UITableView *cTableLabel;

@end

@implementation CourseJobTVC
@synthesize jDetails=_jDetails;

- (id)initWithStyle:(UITableViewStyle)style
{
    self = [super initWithStyle:style];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    _jDetails = (Jobs *)self.jDetails;

    NSString *title1 = _jDetails.jName;
    self.navigationItem.title = title1;
    [self course];
}


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

-(NSArray *)course;
{
    NSString *sqLiteDb = [[NSBundle mainBundle]pathForResource:@"CourseFindr" ofType:@"sqlite"];
    sqlite3_stmt *statement;
    NSMutableArray *retrieve = [[NSMutableArray alloc] init];
    if (sqlite3_open([sqLiteDb UTF8String], &_db) == SQLITE_OK)
    {
        NSString *query= [NSString stringWithFormat:@"SELECT course. * FROM course INNER JOIN jobsCourse ON jobsCourse.courseID = course.cID WHERE jobsCourse.jobID = %d", _jDetails.jID];

        if (sqlite3_prepare_v2(_db, [query UTF8String], -1, &statement, nil) == SQLITE_OK)
        {
            while (sqlite3_step(statement) == SQLITE_ROW)
            {
                int _cID = sqlite3_column_int(statement, 0);
                char *cNameChars = (char *) sqlite3_column_text(statement,1);
                char *cDescChars = (char *) sqlite3_column_text(statement, 2);
                char *cSchoolChars = (char *) sqlite3_column_text (statement, 3);
                char *cProgramChars = (char *) sqlite3_column_text(statement, 4);
                NSString *_cName =cNameChars?[[NSString alloc]initWithUTF8String:cNameChars]:@"";
                NSString *_cDesc = cDescChars?[[NSString alloc]initWithUTF8String:cDescChars]:@"";
                NSString *_cSchool = cSchoolChars?[[NSString alloc]initWithUTF8String:cSchoolChars]:@"";
                NSString *_cProgram = cProgramChars?[[NSString alloc]initWithUTF8String:cProgramChars]:@"";
                Course *courses = [[Course alloc]
                                   initWithCID:_cID
                                   cName:_cName
                                   cDesc:_cDesc
                                   cSchool:_cSchool
                                   cProgram:_cProgram];
                [retrieve addObject:courses];
            }
            sqlite3_finalize(statement);
        }

    }
    return retrieve;
}



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

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
     if(tableView == self.cTableLabel) {NSLog(@"Array count: %d", [self.course count]);
        return [self.course count];}

    return 0;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell ;
    if(tableView != self.cTableLabel){
    //jobName
    cell = [self.tableView dequeueReusableCellWithIdentifier:@"jNameCell"];
    if(cell ==nil)
    { cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"jNameCell"];
        cell.textLabel.text =_jDetails.jName;}

   //jobEarnings
   cell =[self.tableView dequeueReusableCellWithIdentifier:@"jEarningsCell"];
    if(cell ==nil)
    {cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"jEarningsCell"];
        cell.detailTextLabel.text = _jDetails.jEarnings;}

    //jobDesc
    cell =[self.tableView dequeueReusableCellWithIdentifier:@"jDescCell"];
    if(cell == nil)
    { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"jDescLabel"];
        cell.detailTextLabel.text =_jDetails.jDesc;}
   return cell;}

else if(tableView == self.cTableLabel){

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"showCDetails"];
    Course *courses = [self.course objectAtIndex:indexPath.row];
    cell.textLabel.text =courses.cName;
    cell.detailTextLabel.text =courses.cSchool;
    return cell;
}
    return 0;
}

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if([[segue identifier]isEqualToString:@"showCourseDetails"]) {
        CourseTVC  *courseTVC = [segue destinationViewController];

        courseTVC.cDetails = [self.course objectAtIndex:[self.cTableLabel indexPathForSelectedRow].row];
    }
}


@end

My errors were, I can't load the details from the premade UITableView.. and the other UITableView crashes when the array count is more than 2. I've tried the UIViewController with UITableView, but I can't make it scroll when the details exceeds the page.. also it's quite unorganized-looking. I wanted to try the UIViewController with 2 UITableViews but something is really wrong with my code... Please Help.

CRASH REPORT:

*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 4 beyond bounds [0 .. 3]'
*** First throw call stack:
(
    0   CoreFoundation                      0x018325e4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x015b58b6 objc_exception_throw + 44
    2   CoreFoundation                      0x017e69c2 -[__NSArrayI objectAtIndex:] + 210
    3   UIKit                               0x0076415e -[UITableViewDataSource tableView:heightForRowAtIndexPath:] + 127
    4   UIKit                               0x004f5e67 -[UITableViewController tableView:heightForRowAtIndexPath:] + 76
    5   UIKit                               0x0048cb4b __66-[UISectionRowData refreshWithSection:tableView:tableViewRowData:]_block_invoke + 462
    6   UIKit                               0x0048c450 -[UISectionRowData refreshWithSection:tableView:tableViewRowData:] + 4190
    7   UIKit                               0x0048f6bd -[UITableViewRowData numberOfRows] + 98
    8   UIKit                               0x00317db2 -[UITableView noteNumberOfRowsChanged] + 120
    9   UIKit                               0x0031775f -[UITableView reloadData] + 814
    10  UIKit                               0x0031b1c3 -[UITableView _reloadDataIfNeeded] + 65
    11  UIKit                               0x0031fde4 -[UITableView layoutSubviews] + 36
    12  UIKit                               0x002a4267 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 355
    13  libobjc.A.dylib                     0x015c781f -[NSObject performSelector:withObject:] + 70
    14  QuartzCore                          0x03bf02ea -[CALayer layoutSublayers] + 148
    15  QuartzCore                          0x03be40d4 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380
    16  QuartzCore                          0x03be3f40 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 26
    17  QuartzCore                          0x03b4bae6 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 294
    18  QuartzCore                          0x03b4ce71 _ZN2CA11Transaction6commitEv + 393
    19  QuartzCore                          0x03b4d544 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 92
    20  CoreFoundation                      0x017fa4ce __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30
    21  CoreFoundation                      0x017fa41f __CFRunLoopDoObservers + 399
    22  CoreFoundation                      0x017d8344 __CFRunLoopRun + 1076
    23  CoreFoundation                      0x017d7ac3 CFRunLoopRunSpecific + 467
    24  CoreFoundation                      0x017d78db CFRunLoopRunInMode + 123
    25  GraphicsServices                    0x037879e2 GSEventRunModal + 192
    26  GraphicsServices                    0x03787809 GSEventRun + 104
    27  UIKit                               0x00239d3b UIApplicationMain + 1225
    28  CourseFindr                         0x0000768d main + 141
    29  libdyld.dylib                       0x01e6e725 start + 0
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Upvotes: 0

Views: 329

Answers (3)

Saeverix
Saeverix

Reputation: 397

Crash is pretty clear. You are trying to get an object from (NSArray *)course which does not exist...

I think you should start by debugging your code and check how much objects the array actually contains, and how many you are requesting.

Edit: Nevermind, thought I found it but seemed not to be the problem...

Upvotes: 1

SomeGuy
SomeGuy

Reputation: 9700

Because you're mixing table views (especially one with prototype cells) things can get a bit hairy.

To simplify your code I recommend creating them as separate UIViewController subclasses, and then adding one as a child view controller to the other, that way they will have their own delegates, and nothing can get mixed up.

Apple has a good article on this: https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/CreatingCustomContainerViewControllers/CreatingCustomContainerViewControllers.html

Upvotes: 1

Adnan Aftab
Adnan Aftab

Reputation: 14477

A lot of things are wrong in your code. cellforRowAtIndexPath is broken. Actaully in first if block you creating/dequeuing 3 different cells but all are overwriting previous and at end you are returning last one. In prepare you are actually accessing index which is not in array.

Every time you are calling self.course it accualty doing whole fetch processing, I will suggest you create NSMutableArray instance variable, and perform fetch only for first time or when desire.

-(NSArray *)course{
    if(_courseArray!=nil)
       return courseArray;
   //Other wise do fetch

 }

Clean way to deal with this problem is create another viewcontroller and add second tableview in it. Push/present second viewcontroller when a user selects row in first viewController. If you are implementing delegate didSelectRowAtIndexpath: create second viewcontroller and push that and set properties which you want. If you have segue you can create implement this method prepareSegue and set properties in destination viewcontroller. This will make your life easy.

Edit:

Crash which you are having index out of bound, means you are asking for object at index 4 when you are not having any index 4 in array.

Upvotes: 0

Related Questions