18

我对 xcode 很陌生,我正在尝试开发一个示例应用程序,它基本上是一个具有多个级别的嵌入式 tableview。我有一个 plist 存储每个 tableview 的单元格。如果单元格没有孩子,那么我希望能够在按下单元格后转到一个详细视图。最终,我希望能够根据数据类型转到不同的详细视图。为此,我从情节提要创建了一个详细视图,将视图控制器拖到我的详细视图以创建手动“Push”segue,并将 segue 标记为“segue1”。

编辑:这里的源代码

构建手册 Segue

接下来,我填充了我认为它工作的必要函数,即调用[self performSegueWithIdentifier:@"segue1" sender:myString];myString 是我选择的单元格的标题。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    //Check the dictionary to see what cell was clicked
    NSDictionary *dict = [self.tableDataSource objectAtIndex:indexPath.row];
    NSString *myString = [dict objectForKey:@"Title"];
    NSDictionary *dictionary = [self.tableDataSource objectAtIndex:indexPath.row];

    NSArray *children = [dictionary objectForKey:@"Children"];

    //If there is no children, go to the detailed view
    if([children count] == 0)
    {
        [self performSegueWithIdentifier:@"segue1" sender:myString];

    }
    else{
        //Prepare to tableview.
        DrillDownViewController *rvController = [[DrillDownViewController alloc] initWithNibName:nil bundle:[NSBundle mainBundle]];

        //Increment the Current View
        rvController.CurrentLevel += 1;

        //Set the title;
        rvController.CurrentTitle = [dictionary objectForKey:@"Title"];

        //Push the new table view on the stack
        [self.navigationController pushViewController:rvController animated:YES];

        rvController.tableDataSource = children;

    }

}

最后,我调用了 prepare for segue 来寻找标记为 segue1 的 segue。

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if([[segue identifier] isEqualToString:@"segue1"])
    {
        DrillDownDetailController *dvController = [[segue destinationViewController] visibleViewController];
        //DrillDownDetailController *dvController = [[DrillDownDetailController alloc] initWithNibName:nil bundle:[NSBundle mainBundle]];
        [dvController setItemName:(NSString *)sender];
        [self.navigationController pushViewController:dvController animated:YES];
    }
}

我认为这会起作用,但由于某种原因,每当代码到达时[self performSegueWithIdentifier:@"segue1" sender:myString];,它就会因错误而中断

*****终止应用程序由于未捕获的异常'NSInvalidArgumentException',原因: '接收器()没有赛格瑞具有标识符'segue1'' *第一掷调用堆栈:(0x14b4022 0xeb4cd6 0xdf61b 0x3590 0xa85c5 0xa87fa 0x93d85d 0x1488936 0x14883d7 0x13eb790 0x13ead84 0x13eac9b 0x139d7d8 0x139d88a 0x17626 0x23ed 0x2355 0x1)终止调用抛出异常(lldb)

我不明白为什么它告诉我当它已经在故事板和代码中定义时它找不到 segue1。

4

2 回答 2

23

实际上有几个问题:

首先,在您为我们上传的那个项目中,segue 不带有“segue1”标识符:

无标识符

如果您还没有填写该标识符,则应填写该标识符。

其次,当您从表视图推送到表视图时,您正在调用initWithNibName创建视图控制器。你真的想用instantiateViewControllerWithIdentifier.

因此,这行说:

DrillDownViewController *rvController = [[DrillDownViewController alloc] initWithNibName:nil bundle:[NSBundle mainBundle]];

应该说:

DrillDownViewController *rvController = [self.storyboard instantiateViewControllerWithIdentifier:@"TableView"];

第三,你prepareForSegue是:

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if([[segue identifier] isEqualToString:@"segue1"])
    {
        dvController = [[segue destinationViewController] visibleViewController];
        [dvController setItemName:self->nameToSend];
    }
}

并且应该简化以消除对 的引用visibleViewController,例如:

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if([[segue identifier] isEqualToString:@"segue1"])
    {
        dvController = segue.destinationViewController;
        dvController.itemName = nameToSend;
    }
}

第四,你DrillDownDetailController.m有这个方法:

-(void) setItemName:(NSString *)itemName
{
    if(!itemName)
    {
        itemName = [[NSString alloc] initWithString:itemName];
    }
    label.text = itemName;
}

这里有很多问题,但您根本不应该更新label.text这里(因为它可能尚未创建!)。您应该完全消除此自定义设置方法(只需让 Xcode 为您合成标准设置方法)并将您的更改viewDidLoad为如下所示:

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    label.text = self.itemName;
}

viewDidLoad确保在!之前不要更新 UI 对象。

我还没有完成整个程序,但是通过这四个更正,我可以点击“SubItem1”,然后是“Cars”,然后是“BMW”,我会看到一个显示“BMW”的详细信息屏幕。我认为您的 plist 在其他项目上存在一些问题(例如,鞋子条目是字符串,而不是字典条目,您会收到错误消息......我想您只是没有完全填写您的 plist),但上述修复纠正更重要的编码问题。

于 2012-09-20T21:05:49.007 回答
2

主要问题在这里,您正在创建一个空白的 DrillDownViewController,而不是重用情节提要中的那个,请参阅下面代码中的注释

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    {
        if([[segue identifier] isEqualToString:@"segue1"])
        {
             [segue.destinationViewController setItemName:(NSString*)sender];
        }
    }

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
        //Check the dictionary to see what cell was clicked
       NSDictionary *dict = [self.tableDataSource objectAtIndex:indexPath.row];
NSString *titleName = [dict objectForKey:@"Title"];
NSDictionary *dictionary = [self.tableDataSource objectAtIndex:indexPath.row];

NSArray *children = [dictionary objectForKey:@"Children"];

if([children count] == 0)
{
    [self performSegueWithIdentifier:@"segue1" sender:titleName];

}
        else{
    //Prepare to tableview.

    //THE MAIN ISSUE IS HERE, you were creating a blank DrillDownViewController, not reusing the one from storyboards so it did not have a segue at all defined. instead do this:
    UIStoryboard*  sb = [UIStoryboard storyboardWithName:@"MainStoryboard"
                                                  bundle:nil];
    DrillDownViewController *rvController = [sb instantiateViewControllerWithIdentifier:@"DDVC"];       
    //Increment the Current View
    rvController.CurrentLevel += 1;

    //Set the title;
    rvController.CurrentTitle = [dictionary objectForKey:@"Title"];

    //Push the new table view on the stack
    [self.navigationController pushViewController:rvController animated:YES];

    rvController.tableDataSource = children;

}


    }
于 2012-09-20T18:41:50.713 回答