iphone - 如何让向下钻取 TableView 工作?

标签 iphone ios objective-c uitableview

我正在尝试弄清楚如何制作向下钻取的 TableView 。我已经设法从表格 View Cell 转到详细 View ,并且有很多关于如何使用 Storyboard完成此操作的教程。

我想做的是使用 plist 在 TableView 中列出一些数据 - 我让那部分工作正常。我现在想做的是降低几个级别。例如:

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

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

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

我正在使用 iOS7 SDK 和 Xcode 5。

编辑:

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

  1. 我正在使用模型对象——它们从 Plist 中获取数据,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"]; 

我得到的错误:

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

我明白为什么 - 我认为:

rcDeviceListVC.devices

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

所以我试着用这个修改它:

rcDeviceListVC.devices = iDevice.device; 

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

我不确定如何解决这个问题。我想是因为我没有完全理解 prepareForSegue 方法是干什么的?

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

应用现在做什么:

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

或者

  1. 它用顶级数据重新加载 TableView ,并有一个永无止境的向下钻取(循环)

我希望该应用执行的操作:

用它现在正在使用的数据(iPhone、iPad)加载第一个表格 View ——点击一个单元格将列出 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

最佳答案

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

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 link dies - 好的,我为我的问题想出的解决方案:

我意识到:

像我一样使用“可重复使用”的 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 Controller 以正确处理这些数据:

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 名称。所以我将一个数组传递给下一个 View Controller - 然后我在 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 循环从模型数组中提取所有对象——就像我在第一个表格 View 中所做的那样。

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

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

问题

有没有一种方法可以让我重用同一个 UITableView 而我只是错过了它? 这个解决方案是“被接受”还是被认为是“hack”而不是最佳指南?

感谢任何反馈!

关于iphone - 如何让向下钻取 TableView 工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19046121/

相关文章:

iphone - 系统音频播放使运行iOS 4.2.1的iPhone保持静音

ios - 如何从 JSON NSDictionary 创建对象

iphone - 自动更改到下一个 ViewController

c++ - NSURLConnection 和 NSURLRequest 的纯 C++ 等价物

iphone - iPhone 的 Sprite 表生成器?

ios - iOS 中通过 wifi 的点对点网络

ios - Tinder 在 Objective-c 中加载照片的算法。用 Parse.com 复制它

IOS/objective-C : Convert standard UIColor to CGColor

iphone - 如何保存/加载 NSUserDefaults 以进行备份?

c++ - 混合 Objective C ,(*.m , *.mm & .c/.cpp ) 文件