通过storyboard和xcode正确创build手动search

我很新的xcode,我试图开发一个示例应用程序,基本上是一个embedded式的tableview有很多层次。 我有一个plist存储每个tableview的单元格。 如果细胞没有孩子,那么一旦细胞被按下,我希望能够进入一个详细的视图。 最终,我希望能够根据数据types去不同的详细视图。 为了做到这一点,我创build了一个故事板的详细视图,拖动我的视图控制器到我的详细视图,以创build一个手动的“推”segue,并标记为segue“segue1”。

编辑:源代码在这里

建筑手册Segue

接下来我填充我认为是这个工作的必要function,即调用[self performSegueWithIdentifier:@"segue1" sender:myString]; 其中myString是我select的单元格的标题。

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

最后,我打电话给准备寻找segue的segue1。

 -(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]; ,它打破了错误

*****终止应用程序由于未捕获的exception“NSInvalidArgumentException”,原因:“Receiver()没有与标识符”segue1“ *第一个抛出调用堆栈:0x14b4022 0xeb4cd6 0xdf61b 0x3590 0xa85c5 0xa87fa 0x93d85d 0x1488936 0x14883d7 0x13eb790 0x13ead84 0x13eac9b 0x139d7d8 0x139d88a 0x17626 0x23ed 0x2355 0x1)终止调用抛出exception(lldb)

我不知道为什么它告诉我,它已经定义在故事板和代码中找不到segue1。

实际上有几个问题:

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

没有标识符

如果你还没有,你应该填写这个标识符。

其次 ,当你从表视图推送到表视图时,你调用initWithNibName来创build一个视图控制器。 你真的想使用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 (因为它可能还没有被创build!)。 你应该完全消除这个自定义的setter方法(只要让Xcode为你合成标准的setter),只需要将你的viewDidLoad改为如下所示:

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

确保你不更新UI对象,直到viewDidLoad

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

主要问题在这里,您正在创build一个空白的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; } }