在视图控制器之间移动和传递数据的正确方法

时间:2012-08-05 15:40:52

标签: ios uinavigationcontroller segue

我的根控制器是一个带静态单元格和导航控制器的TableViewController。 根据选择的单元格,我想推送另一个ViewController(带有嵌入式TableView),它将相应地更改其配置(按钮是否启用,单元格数据来自db表或NSArray等)。 选择一些“控制器A”单元将调用“控制器B”或“控制器C”并传递一些数据。

我正在尝试的代码如下所示:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
   switch (indexPath.row) {
        case 0:
        {
            [self performSegueWithIdentifier:@"segueToType" sender:self];
        }
            break;
        case 1:
        {
            [self performSegueWithIdentifier:@"segueToType" sender:self];
        }
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{

if ([[segue identifier] isEqualToString:@"segueToType"])
{
    NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];
    NSInteger rowNumber = selectedIndexPath.row;
    switch (rowNumber) {
        case 0:
        {
            TypeSelectController *selCon = [segue destinationViewController];
            selCon.myPet = self.myPet;
            selCon.sel = @"tipo";
            selCon.delegate = self;
        }
            break;
        case 1:
        {
            TypeSelectController *selCon = [segue destinationViewController];
            selCon.myPet = self.myPet;
            selCon.sel = @"razza";
            selCon.delegate = self;
        }
            break;
        default:
            break;
    }

} 
}

在这种情况下,例如,我只调用“控制器B”,但根据所选单元格“控制器A”,它以不同的方式配置自身(取决于“selCon.sel”字符串)。

在“控制器B”中,我有这样的代码:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([sel isEqualToString:@"tipo"]) {
    NSString *itemToPassBack = [tipi objectAtIndex:indexPath.row];
    [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack ofType:@"tipo"];
    [self.navigationController popViewControllerAnimated:YES];
} else if ([sel isEqualToString:@"razza"]) {
    NSString *itemToPassBack = [razze objectAtIndex:indexPath.row];
    [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack ofType:@"razza"];
    [self.navigationController popViewControllerAnimated:YES];
}
}

所以再次,根据字符串“sel”值,我将不同的数据返回到“控制器A”。

当我选择控制器A中的第一个单元格时,我正确地获得了控制器B场景。然后我选择一个单元格并使用正确的数据返回控制器A. 现在,如果我尝试在控制器A中选择第二个单元并在控制器B中选择一个单元,则导航不会按我的意愿响应,我得到控制器C场景,然后是控制器A和以下错误:

嵌套推送动画可能导致导航栏损坏

在意外状态下完成导航转换。导航栏子视图树可能已损坏。

对于开始/结束外观转换的不平衡调用。

我做错了什么?

2 个答案:

答案 0 :(得分:0)

在故事板示例中使用协议和委托的快速示例。只是点击这里的亮点,因为你已经完成了大部分工作。

控制器a(父级)。有一个名为category的NSString属性和一个名为partNumber的属性。有一个tableview。选择行以启动segue。 [self performSegueWithIdentifier:@“segueToType”sender:self];

  • (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

if([[segue identifier] isEqualToString:@“segueToType”]) {
   ControllerB * b = segue.destinationViewController;    b.category = self.category;    b.delegate = self; }

查看控制器B

@protocol - (void)doSomethingWithPickedPartNumber:(NSString *)partNumber; @end

//使用传入类别的partnumbers设置tableview。

选择了

//行,所以我们有了要发回的partNumber。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *pn = [self.listOfParts objectAtIndex:indexPath.row];

 //options - set the variable in the parent or call a method in the parent
 self.delegate.partNumber = pn;
 //if you set the variable in the parent - you can check for it in the -(void)viewWillAppear  method and reconfigure the parent view if needed

 //or do this
 [self.delegate doSomethingWithPickedPartNumber:pn];

 //this is actually calling a method in the parent.  remember you don't have a view you can see yet, but its in memory and you can modify things so when the child pops back it will look how you want it.  Also note, you can name the protocol methods what ever you want, as long as they match up from the parent  to the protocol in the child.


 //then return to parent
 [self.navigationController popViewControllerAnimated:YES];

}

答案 1 :(得分:0)

好的,再试一次。

  • 让我们使用头发颜色示例。你在控制器a中有一个表,有一个静态单元格用于发色。假设您显示所选颜色的文本值。 cell.textLabel = self.hairColor。如果为空白,则用户可以触摸单元格并打开新控制器以选择颜色。

在你想要的新视图控制器中,你设置一个属性来告诉它查找“hairColor”。所以它从一个名为listOfHairChoices的db构建一个列表。

用户选择第3行,因此您可以使用您的委托引用在父级中设置属性,如下所示。 self.delegate.hairColor = [self.listOfHairChoices objectAtIndex:indexPath.row]; 然后pop关闭子vc并弹回父级。 [self.navigationController popViewCon..etc]

然后回到父级,在 - (void)viewDidAppear中你只需重新加载你的tableview:[self.tableView reloadData]

现在,您的原始tableview应显示在子视图控制器中选择的单元格的值。

这是一种直接的方式,并且每一步都需要逻辑来确定您正在使用哪个属性以及需要设置哪个属性 - 但这将适用于您现有的框架。

另一种方法是创建您正在呈现的数据的模型类,然后将模型传递给子VC - 让他们更新模型并将其传回,然后只需在每个模型后重新加载您的表过渡。您可能不熟悉这种方法,但它简化了事情并减少了现在对于tableview的每一行所具有的所有条件逻辑。

希望这个建议可以帮助您完成项目。