1

我试图弄清楚如何做一个向下钻取的表格视图。我已经设法从表格视图单元格转到详细视图,并且有很多关于如何使用情节提要完成的教程。

我想要做的是使用 plist 在表格视图中列出一些数据 - 我的那部分工作正常。我现在想做的就是往下走几个层次。例如:

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

现在我似乎能做的就是:顶级-> 详细视图。

我只需要了解如何 - 当点击一个单元格时,它将在下一级加载该单元格的数据 - 就像某种类别一样。

我正在使用 iOS7 SDK 和 Xcode 5。

编辑:

所以我查看了其他一些教程并根据我的需要对其进行了修改——这是我需要做的,也是我正在做的:

  1. 我正在使用模型对象——它们从 Plist 中获取数据,其中根对象是字典。
  2. 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>
    

所以现在我将 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;

}

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

然后我像这样填充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;
}

然后这就是我卡住的地方:

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


            }
}

该应用程序因以下行而崩溃:

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

我得到的错误:

[*** 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“-[RCDevice objectForKeyedSubscript:]:无法识别的选择器发送到实例 0xed4aff0”

我明白为什么 - 我认为:

rcDeviceListVC.devices

是一个用我的 loadData 方法填充的 RCDevice 对象的数组 - 它不知道是什么rowData[@"devices"]

所以我试图用这个来修改它:

rcDeviceListVC.devices = iDevice.device; 

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

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

对于实际的向下钻取 - 我正在使用环回 segue 并重用 RCDDeviceListVC。

该应用程序现在做什么:

  1. 它在 Tableview 中加载正确的数据。当我选择一个单元格时 - prepareForSegue 方法被调用 - 应用程序崩溃。

或者

  1. 它使用顶级数据重新加载表视图,并具有永无止境的向下钻取(循环)

我希望应用程序做什么:

使用它现在使用的数据(iPhone、iPad)加载第一个 tableview - 点击一个单元格将列出 iPad 或 iPhone 的型号。

我究竟做错了什么?

更新

这是我尝试编辑以与我的自定义对象一起使用的原始代码示例 - 而不是使用 NSDictionaries。

我用我的 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"];
    }
}

为什么它适用于上述 - 但不是当我尝试使用我的自定义对象时?

RC设备

4

1 回答 1

1

好的,经过大量调试和使用代码 - 这就是我想出的:请参阅我的上一篇文章:

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

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

我意识到:

像我一样使用“可重复使用”的 UITableViewController 给我带来的问题比我知道的要多。我的问题是试图导航我的数据源并使用相同的 tableview 重新加载具有新对象的 tableview 被证明是一个问题。

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

我修改了 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>

现在我需要重新设计 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!

我得出的结论是,我正在为 iDevice.name 传递一个 NSString,而我想要的是一个 NSArray 名称。所以我将一个数组传递给下一个视图控制器 - 然后我这样做了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;
}

我在这里使用 for 循环从模型数组中提取所有对象 - 就像我在第一个 tableview 中所做的一样。

以上正是我需要的,并且可以 100% 工作!

使用调试器来观察我的代码在做什么以及它传递了什么值等确实帮助我找到了解决方案。

问题

有没有办法我可以重用相同的 UITableView 而我只是错过了它?这个解决方案是“接受”还是被认为是“黑客”而不是最好的指南?

感谢任何反馈!

于 2013-10-01T18:11:34.570 回答