Reputation: 133
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
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
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
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