如何让下钻的表视图工作?

时间:2022-10-30 09:32:47

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.

我正在试图弄清楚如何做一个向下的表格视图。我已经成功地从一个表视图单元格切换到一个详细的视图,并且有很多教程介绍如何使用故事板来实现这一点。

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:

我要做的是使用plist在表视图中列出一些数据——我让这个部分工作得很好。我现在想做的是降低一些水平。例如:

Top level --> Level 1 --> level 2 --> etc --> detailed view. 

Right now all I can seem to do is: Top level --> detailed view.

现在我所能做的就是:*的>详细视图。

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.

我只需要理解—当点击一个单元时,它将在下一层为该单元加载数据—就像某种类别。

I'm using the iOS7 SDK and Xcode 5.

我使用的是iOS7 SDK和Xcode 5。

Edit:

编辑:

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:

所以我看了一些其他的教程并根据我的需要修改了它们——这就是我需要做的和我正在做的:

  1. I'm using model objects - they get their data from a Plist, which root object is a Dictionary.
  2. 我使用的是模型对象——它们从Plist获取数据,而Plist的根对象是一个字典。
  3. In the Plist data is like so:

    Plist数据如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>name</key>
        <string>iDevices</string>
        <key>devices</key>
        <array>
            <dict>
                <key>name</key>
                <string>iPhones</string>
                <key>devices</key>
                <array>
                    <dict>
                        <key>name</key>
                        <string>1St Generation</string>
                    </dict>
                </array>
            </dict>
            <dict>
                <key>name</key>
                <string>iPads</string>
                <key>devices</key>
                <array>
                    <dict>
                        <key>name</key>
                        <string>1St Generation</string>
                    </dict>
                </array>
            </dict>
        </array>
    </dict>
    </plist>
    

So now I loaded the Plist into a custom data object and then I am using this object to populate an NSMutableArray like so:

现在我将Plist加载到一个自定义数据对象中然后使用这个对象来填充一个NSMutableArray,如下所示:

-(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;

}

I call this method from my viewDidLoad on root TVC. Data loads correctly.

我从根TVC上的viewDidLoad调用这个方法。数据加载正确。

Then I fill the tableView like so:

然后填充tableView:

- (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;
}

Then this is where I am getting stuck:

这就是我被困住的地方:

   - (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!


            }
}

The app crashes with this line:

这款应用程序就这样崩溃了:

rcDeviceListVC.devices = rowData[@"devices"]; 

The error I get:

我收到的错误:

[*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[RCDevice objectForKeyedSubscript:]: unrecognized selector sent to instance 0xed4aff0'

[***终止app由于未捕获异常'NSInvalidArgumentException',原因:'-[RCDevice objectForKeyedSubscript:]::发送给实例0xed4aff0的未识别选择器'

Which I see why -I think:

我明白为什么,我想:

rcDeviceListVC.devices

rcDeviceListVC.devices

Is an array filled with RCDevice objects from my loadData method - it doesn't know what rowData[@"devices"] is.

是一个数组,其中包含来自我的loadData方法的RCDevice对象——它不知道什么是rowData[@"devices"]。

So I tried to modify that with this:

我试着修改一下

rcDeviceListVC.devices = iDevice.device; 

But that means I have an incompatible pointer. (NSString to an NSArray)

但这意味着我有一个不相容的指针。(NSString NSArray)

I am not sure how to fix this. I think it's because I don't fully understand what the prepareForSegue method is doing?

我不知道如何解决这个问题。我想是因为我不完全理解prepareForSegue方法在做什么?

For the actual drill down - I am using a loopback segue and reusing the RCDDeviceListVC.

对于实际的下钻——我正在使用一个环回segue并重用RCDDeviceListVC。

What the app does now:

这款应用现在的功能是:

  1. It loads with the correct data in a Tableview. When I select a cell - the prepareForSegue method gets called - app crashes.
  2. 它在Tableview中装载正确的数据。当我选择一个单元格时- prepareForSegue方法会被调用- app崩溃。

Or

  1. It reloads the table view with the top level data and has a never ending drill down (loop)
  2. 它使用*别的数据重新加载表视图,并有一个永无休止的向下钻取(循环)

What I want the app to do:

我想让应用做的是:

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.

将当前使用的数据(iphone、ipad)加载到第一个桌面视图中——点击一个单元就会列出ipad或iphone的模型。

What am I doing wrong?

我做错了什么?

Update:

更新:

This is the original code sample I tried to edit to use with my custom objects - instead of using NSDictionaries.

这是我尝试编辑的用于自定义对象的原始代码示例,而不是使用nsdictionary。

I tested out this code sample with my Plist and it works exactly as I need it to:

我用我的Plist测试了这个代码示例,它完全按照我的需要工作:

- (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"];
    }
}

Why does it work with the above - but not when I try use my custom object?

为什么它可以使用上面的-但是当我尝试使用我的自定义对象时却不能?

RCDevice

RCDevice

1 个解决方案

#1


1  

Okay so after a lot of debugging and playing with the code - this is what I came up with: see my last post:

经过大量的调试和调试之后——这就是我的想法:看我的最后一篇文章:

http://www.iphonedevsdk.com/forum/iphone-sdk-development/115623-drill-down-tableviews-need-a-push-in-the-right-direction-update-almost-got-it.html#latest

http://www.iphonedevsdk.com/forum/iphone-sdk-development/115623-drill-down-tableviews-need-a-push-in-the-right-direction-update-almost-got-it.html最新

Edit: Incase link dies - Okay so the solution I came up with for my problem:

编辑:Incase链接死-好的,所以我的问题的解决方案:

What I realised:

我意识到:

Using a 'reusable' UITableViewController like I was doing was giving me more issues than I knew what to do with. My issue was trying to navigate my data source and reloading the tableview with new objects one level down using the same tableview was proving to be an issue.

使用一个“可重用的”UITableViewController就像我所做的那样会给我带来比我知道该怎么做更多的问题。我的问题是试图导航我的数据源,用新对象重新加载tableview,使用相同的tableview,在一层以下,被证明是一个问题。

This is how I eventually solved the problem:

这就是我最终解决问题的方法:

I reworked the Plist file to store data like so:

我对Plist文件进行了重构,以存储如下数据:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>name</key>
    <string>iDevice</string>
    <key>devices</key>
    <array>
        <dict>
            <key>name</key>
            <string>iPhones</string>
            <key>devices</key>
            <array>
                <dict>
                    <key>name</key>
                    <string>1St Generation</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>3G</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>3GS</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>4</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>4S</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>5</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>5S</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>5C</string>
                </dict>
            </array>
        </dict>
        <dict>
            <key>name</key>
            <string>iPads</string>
            <key>devices</key>
            <array>
                <dict>
                    <key>name</key>
                    <string>1St Generation</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>2</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>3</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>4</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>Mini</string>
                </dict>
            </array>
        </dict>
    </array>
</dict>
</plist>

Now I needed to rework the RCDeviceListView controller to go through this data properly:

现在我需要重新设计RCDeviceListView控制器来正确地检查这些数据:

RCDeviceListView.m

-

- - - - - -

 (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    UITableViewCell *cell = (UITableViewCell *)sender;

    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];

    RCDevice *iDevice = self.devices[indexPath.row];

    if ([segue.identifier isEqualToString:@"ModelViewSegue"]) {
        RCModelViewController *rcModelVC = (RCModelViewController *)segue.destinationViewController;

        rcModelVC.models = iDevice.device;
        rcModelVC.title = iDevice.name;



            //--Checking object for valid string--//
        NSLog(@"Object: %@", iDevice.device);


    }else if ([segue.identifier isEqualToString:@"detailSegue"]){

        __unused RCDeviceDetailView *rcDeviceDVC = (RCDeviceDetailView *)segue.destinationViewController;
    }
}       //TODO Fille this in!

I came to the conclusion that I was passing an NSString for iDevice.name and what I was wanting was an NSArray of names. So I passed an array to the next view controller - then I did this in RCModelViewController:

我得出的结论是,我为idevice.com传递了一个NSString。name我想要的是一个NSArray的name。我给下一个视图控制器传递了一个数组然后我在RCModelViewController中做了这个

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

-(void) loadData

{
    NSMutableArray *allModels = [NSMutableArray array];
    for (NSDictionary *deviceModels in self.models)
        {

        RCDevice *models = [[RCDevice alloc]initWithDictionary:deviceModels];

        [allModels addObject:models];

        }
    self.dictModels = allModels;
}
#pragma mark - Table view data source


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

    // Return the number of rows in the section.
    return [self.dictModels count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ModelCell"];

    RCDevice *device = self.dictModels[indexPath.row];

    cell.textLabel.text = device.name;

    return cell;
}

I used the for loop here to pull out all the objects from the models array - much like I did in the first tableview.

我在这里使用for循环从models数组中取出所有的对象——就像我在第一个tableview中所做的那样。

The above does exactly what I need and works 100%!

以上就是我所需要的,并且100%有效!

Using the debugger to watch what my code was doing and what values it was passing etc really helped me towards a solution.

使用调试器来监视我的代码在做什么,它传递了什么值等等,这确实帮助我找到了解决方案。

Question

问题

Was there a way I could have reused the same UITableView and I just missed it? Is this solution 'accepted' or is this considered a 'hack' and not a best guide at all?

是否有一种方法我可以重复使用相同的UITableView,而我只是错过了它?这一解决方案是“被接受”还是被认为是“黑客”而不是最佳指南?

Appreciate any feedback!

欣赏任何反馈!

#1


1  

Okay so after a lot of debugging and playing with the code - this is what I came up with: see my last post:

经过大量的调试和调试之后——这就是我的想法:看我的最后一篇文章:

http://www.iphonedevsdk.com/forum/iphone-sdk-development/115623-drill-down-tableviews-need-a-push-in-the-right-direction-update-almost-got-it.html#latest

http://www.iphonedevsdk.com/forum/iphone-sdk-development/115623-drill-down-tableviews-need-a-push-in-the-right-direction-update-almost-got-it.html最新

Edit: Incase link dies - Okay so the solution I came up with for my problem:

编辑:Incase链接死-好的,所以我的问题的解决方案:

What I realised:

我意识到:

Using a 'reusable' UITableViewController like I was doing was giving me more issues than I knew what to do with. My issue was trying to navigate my data source and reloading the tableview with new objects one level down using the same tableview was proving to be an issue.

使用一个“可重用的”UITableViewController就像我所做的那样会给我带来比我知道该怎么做更多的问题。我的问题是试图导航我的数据源,用新对象重新加载tableview,使用相同的tableview,在一层以下,被证明是一个问题。

This is how I eventually solved the problem:

这就是我最终解决问题的方法:

I reworked the Plist file to store data like so:

我对Plist文件进行了重构,以存储如下数据:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>name</key>
    <string>iDevice</string>
    <key>devices</key>
    <array>
        <dict>
            <key>name</key>
            <string>iPhones</string>
            <key>devices</key>
            <array>
                <dict>
                    <key>name</key>
                    <string>1St Generation</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>3G</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>3GS</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>4</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>4S</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>5</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>5S</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>5C</string>
                </dict>
            </array>
        </dict>
        <dict>
            <key>name</key>
            <string>iPads</string>
            <key>devices</key>
            <array>
                <dict>
                    <key>name</key>
                    <string>1St Generation</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>2</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>3</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>4</string>
                </dict>
                <dict>
                    <key>name</key>
                    <string>Mini</string>
                </dict>
            </array>
        </dict>
    </array>
</dict>
</plist>

Now I needed to rework the RCDeviceListView controller to go through this data properly:

现在我需要重新设计RCDeviceListView控制器来正确地检查这些数据:

RCDeviceListView.m

-

- - - - - -

 (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    UITableViewCell *cell = (UITableViewCell *)sender;

    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];

    RCDevice *iDevice = self.devices[indexPath.row];

    if ([segue.identifier isEqualToString:@"ModelViewSegue"]) {
        RCModelViewController *rcModelVC = (RCModelViewController *)segue.destinationViewController;

        rcModelVC.models = iDevice.device;
        rcModelVC.title = iDevice.name;



            //--Checking object for valid string--//
        NSLog(@"Object: %@", iDevice.device);


    }else if ([segue.identifier isEqualToString:@"detailSegue"]){

        __unused RCDeviceDetailView *rcDeviceDVC = (RCDeviceDetailView *)segue.destinationViewController;
    }
}       //TODO Fille this in!

I came to the conclusion that I was passing an NSString for iDevice.name and what I was wanting was an NSArray of names. So I passed an array to the next view controller - then I did this in RCModelViewController:

我得出的结论是,我为idevice.com传递了一个NSString。name我想要的是一个NSArray的name。我给下一个视图控制器传递了一个数组然后我在RCModelViewController中做了这个

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

-(void) loadData

{
    NSMutableArray *allModels = [NSMutableArray array];
    for (NSDictionary *deviceModels in self.models)
        {

        RCDevice *models = [[RCDevice alloc]initWithDictionary:deviceModels];

        [allModels addObject:models];

        }
    self.dictModels = allModels;
}
#pragma mark - Table view data source


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

    // Return the number of rows in the section.
    return [self.dictModels count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ModelCell"];

    RCDevice *device = self.dictModels[indexPath.row];

    cell.textLabel.text = device.name;

    return cell;
}

I used the for loop here to pull out all the objects from the models array - much like I did in the first tableview.

我在这里使用for循环从models数组中取出所有的对象——就像我在第一个tableview中所做的那样。

The above does exactly what I need and works 100%!

以上就是我所需要的,并且100%有效!

Using the debugger to watch what my code was doing and what values it was passing etc really helped me towards a solution.

使用调试器来监视我的代码在做什么,它传递了什么值等等,这确实帮助我找到了解决方案。

Question

问题

Was there a way I could have reused the same UITableView and I just missed it? Is this solution 'accepted' or is this considered a 'hack' and not a best guide at all?

是否有一种方法我可以重复使用相同的UITableView,而我只是错过了它?这一解决方案是“被接受”还是被认为是“黑客”而不是最佳指南?

Appreciate any feedback!

欣赏任何反馈!