如何使钻取tableviews工作?

时间:2013-09-27 08:25:00

标签: iphone ios objective-c uitableview

我正在试图弄清楚如何进行深入研究的表格视图。我已经设法从表格视图Cell转到详细视图,并且有很多关于如何使用故事板完成的教程。

我要做的是使用plist在Table视图中列出一些数据 - 我的部分工作正常。我现在想做的是下几级。例如:

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

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

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

我正在使用iOS7 SDK和Xcode 5.

修改:

所以我查看了其他一些教程并根据我的需要对其进行了修改 - 这就是我需要做的和我正在做的事情:

  1. 我正在使用模型对象 - 他们从Plist获取数据,根对象是Dictionary。
  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>
    
  3. 所以现在我将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方法在做什么?

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

    该应用现在的作用:

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

      1. 它使用顶级数据重新加载表视图,并且具有永无止境的向下钻取(循环)
      2. 我希望该应用做什么:

        使用现在使用的数据加载第一个tableview(iPhone,iPad) - 点击一个单元格会列出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"];
            }
        }
        

        为什么它适用于上述内容 - 但是当我尝试使用自定义对象时却没有?

          

        RCDevice

1 个答案:

答案 0 :(得分: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#latest

编辑: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而我错过了它? 这个解决方案是“被接受”还是被认为是“黑客”,而不是最好的指南?

感谢任何反馈!