Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to get drill-down tableviews working?
    text
    copied!<p>I am trying to figure out how to do a table view that drills down. I've manage to go from a table view Cell to a detailed view, and there are plenty of tutorials on how that's done with storyboards. </p> <p>What I am trying to do is list some data in a Table view using a plist - I have that part working fine. What I now want to do is go down a few levels. For example: </p> <pre><code>Top level --&gt; Level 1 --&gt; level 2 --&gt; etc --&gt; detailed view. </code></pre> <p>Right now all I can seem to do is: Top level --> detailed view. </p> <p>I just need to understand how - when tapping on one cell it will load the data for that cell in the next level down - like a category of some sort. </p> <p>I'm using the iOS7 SDK and Xcode 5. </p> <p><strong>Edit:</strong> </p> <p>So I looked at some other tutorials and modified them to my needs - this is what I need to do and what I am doing:</p> <ol> <li>I'm using model objects - they get their data from a Plist, which root object is a Dictionary. </li> <li><p>In the Plist data is like so: </p> <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt; &lt;plist version="1.0"&gt; &lt;dict&gt; &lt;key&gt;name&lt;/key&gt; &lt;string&gt;iDevices&lt;/string&gt; &lt;key&gt;devices&lt;/key&gt; &lt;array&gt; &lt;dict&gt; &lt;key&gt;name&lt;/key&gt; &lt;string&gt;iPhones&lt;/string&gt; &lt;key&gt;devices&lt;/key&gt; &lt;array&gt; &lt;dict&gt; &lt;key&gt;name&lt;/key&gt; &lt;string&gt;1St Generation&lt;/string&gt; &lt;/dict&gt; &lt;/array&gt; &lt;/dict&gt; &lt;dict&gt; &lt;key&gt;name&lt;/key&gt; &lt;string&gt;iPads&lt;/string&gt; &lt;key&gt;devices&lt;/key&gt; &lt;array&gt; &lt;dict&gt; &lt;key&gt;name&lt;/key&gt; &lt;string&gt;1St Generation&lt;/string&gt; &lt;/dict&gt; &lt;/array&gt; &lt;/dict&gt; &lt;/array&gt; &lt;/dict&gt; &lt;/plist&gt; </code></pre></li> </ol> <p>So now I loaded the Plist into a custom data object and then I am using this object to populate an NSMutableArray like so: </p> <pre><code>-(void)loadData{ NSString *plistPath = [[NSBundle mainBundle]pathForResource:@"masterDeviceList" ofType:@"plist"]; NSDictionary *deviceListDict = [NSDictionary dictionaryWithContentsOfFile:plistPath]; NSArray *allDevices = deviceListDict[@"devices"]; NSMutableArray *iDevices = [NSMutableArray array]; for (NSDictionary *dictionary in allDevices){ RCDevice *iDevice = [[RCDevice alloc]initWithDictionary:dictionary]; [iDevices addObject:iDevice]; } self.devices = iDevices; } </code></pre> <p>I call this method from my viewDidLoad on root TVC. Data loads correctly. </p> <p><strong>Then I fill the tableView like so:</strong></p> <pre><code>- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell* cell; RCDevice *iDevice = self.devices[indexPath.row]; if (iDevice.device) { cell = [tableView dequeueReusableCellWithIdentifier:LoopBackCell]; } else { cell = [tableView dequeueReusableCellWithIdentifier:DetailCell]; } cell.textLabel.text = iDevice.name; return cell; } </code></pre> <p><strong>Then this is where I am getting stuck:</strong> </p> <pre><code> - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { UITableViewCell *cell = (UITableViewCell *)sender; NSIndexPath *indexPath = [self.tableView indexPathForCell:cell]; NSDictionary *rowData = self.devices[indexPath.row]; //Testing with this type RCDevice *iDevice = self.devices[indexPath.row]; //Also testing with custom object if ([self.devices[indexPath.row]isKindOfClass:[NSDictionary class]]) { if ([segue.identifier isEqualToString:@"loopbackSegue"]) { RCDeviceListView *rcDeviceListVC = (RCDeviceListView *)segue.destinationViewController; //TODO: Check if this gets called }else if ([segue.identifier isEqualToString:@"detailSegue"]){ __unused RCDeviceDetailView *rcDeviceDVC = (RCDeviceDetailView *)segue.destinationViewController; //TODO Fille this in! } } else { if ([self.devices[indexPath.row]isKindOfClass:[RCDevice class]]) { if ([segue.identifier isEqualToString:@"loopbackSegue"]) { RCDeviceListView *rcDeviceListVC = (RCDeviceListView *)segue.destinationViewController; rcDeviceListVC.devices = iDevice.device; //This crashes rcDeviceListVC.devices = rowData[@"devices"]; //Also crashes rcDeviceListVC.title = iDevice.name; }else if ([segue.identifier isEqualToString:@"detailSegue"]){ __unused RCDeviceDetailView *rcDeviceDVC = (RCDeviceDetailView *)segue.destinationViewController; } } //TODO Fille this is! } } </code></pre> <p><strong>The app crashes with this line:</strong></p> <pre><code>rcDeviceListVC.devices = rowData[@"devices"]; </code></pre> <p><strong>The error I get:</strong> </p> <blockquote> <p>[*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[RCDevice objectForKeyedSubscript:]: unrecognized selector sent to instance 0xed4aff0'</p> </blockquote> <p><strong>Which I see why -I think:</strong></p> <blockquote> <p>rcDeviceListVC.devices</p> </blockquote> <p>Is an array filled with RCDevice objects from my loadData method - it doesn't know what <code>rowData[@"devices"]</code> is. </p> <p><strong>So I tried to modify that with this:</strong> </p> <pre><code>rcDeviceListVC.devices = iDevice.device; </code></pre> <p>But that means I have an incompatible pointer. (NSString to an NSArray) </p> <p>I am not sure how to fix this. I think it's because I don't fully understand what the prepareForSegue method is doing? </p> <p>For the actual drill down - I am using a loopback segue and reusing the RCDDeviceListVC. </p> <p><strong>What the app does now:</strong></p> <ol> <li>It loads with the correct data in a Tableview. When I select a cell - the prepareForSegue method gets called - app crashes. </li> </ol> <p>Or</p> <ol start="2"> <li>It reloads the table view with the top level data and has a never ending drill down (loop) </li> </ol> <p><strong>What I want the app to do:</strong></p> <p>Load the first tableview with the data it's using now (iPhones, iPads) - tapping on a cell would list models of either iPads or the iPhones. </p> <p>What am I doing wrong?</p> <p><strong>Update</strong>: </p> <p>This is the original code sample I tried to edit to use with my custom objects - instead of using NSDictionaries. </p> <p>I tested out this code sample with my Plist and it works exactly as I need it to: </p> <pre><code>- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { UITableViewCell* cell = (UITableViewCell*)sender; NSIndexPath* indexPath = [self.tableView indexPathForCell:cell]; NSDictionary* rowData = [self.items objectAtIndex:indexPath.row]; if ([segue.identifier isEqualToString:@"loopbackSegue"]) { DrillTableController* drillVC = (DrillTableController*)segue.destinationViewController; drillVC.items = [rowData objectForKey:@"items"]; drillVC.title = [rowData objectForKey:@"name"]; } else if ([segue.identifier isEqualToString:@"detailSegue"]) { DetailsController* detailVC = (DetailsController*)segue.destinationViewController; detailVC.name = [rowData objectForKey:@"name"]; //detailVC.imageName = [rowData objectForKey:@"imageName"]; } } </code></pre> <p>Why does it work with the above - but not when I try use my custom object? </p> <blockquote> <p>RCDevice</p> </blockquote>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload