通过storyboard和xcode正确创build手动search
我很新的xcode,我试图开发一个示例应用程序,基本上是一个embedded式的tableview有很多层次。 我有一个plist存储每个tableview的单元格。 如果细胞没有孩子,那么一旦细胞被按下,我希望能够进入一个详细的视图。 最终,我希望能够根据数据types去不同的详细视图。 为了做到这一点,我创build了一个故事板的详细视图,拖动我的视图控制器到我的详细视图,以创build一个手动的“推”segue,并标记为segue“segue1”。
编辑:源代码在这里
接下来我填充我认为是这个工作的必要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; } }