在视图控制器之间传递行选择

3
使用Storyboard,我目前有一个静态的UITableView。 当用户从父表视图中选择一行时,将显示一个新的表视图以显示某些选项。 一旦用户从新的表视图中选择一行,我想关闭表格并显示父视图控制器,并在单元格中显示用户选择。它就像一个表单的单选按钮。
我该如何处理视图控制器的关闭和数据的传递?应该在哪个方法中处理,viewWillAppear还是didSelectRowAtIndexPath?我已经困扰了一段时间。
3个回答

9

使用 委托。子视图控制器定义了一个委托协议,由父视图控制器实现。在父视图控制器显示子视图控制器之前,它将自身设置为子视图控制器的委托。当用户在子视图中选择了一行或其他内容时,子视图控制器会调用其委托的方法并关闭自身。


我为您写了一个示例代码:https://github.com/vikingosegundo/StateSelection

父视图控制器是MasterViewController。
子视图控制器是StateSelectionViewController。

  • The StateSelectionViewController defines a protocol in it's header: StateSelectionDelegate and has a delegate property id<StateSelectionDelegate> delegate.

    @protocol StateSelectionDelegate <NSObject>
    -(void) selectedState:(NSString *)state forNation:(NSString *)nation;
    @end  
    
  • MasterViewController conforms to this protocol, it implements the only delegate method selectedState:forNation:.

    -(void)selectedState:(NSString *)state forNation:(NSString *)nation
    {
        self.statesDictionray[nation] = state;
        [self.tableView reloadData];
    }
    
  • During MasterViewController's prepareForSegue:, it sets itself a delegate of the destination view controller, which happen to be StateSelectionViewController.

    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    {
        if ([[segue identifier] isEqualToString:@"showDetail"]) {
            NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
            NSString *selectedNation =[[[self.tableView cellForRowAtIndexPath:indexPath] textLabel] text];
            [[segue destinationViewController] setSelectedNation:selectedNation];
            [[segue destinationViewController] setDelegate:self];
        }
    }
    
  • Now the segue is executed and the StateSelectionViewController's tableview gets displayed.

  • Once the user tabs on one of the rows, StateSelectionViewController will call

    [self.delegate selectedState: <theState> forNation: <theNation>];
    

    and dismisses or pops itself. Note the switch to determine the way the controller was presented.

    -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
           [self.delegate selectedState:stateDictionary[_selectedNation][indexPath.row] forNation:_selectedNation];
           if(self.presentingViewController)
               [self dismissViewControllerAnimated:NO completion:NULL];
           else
               [self.navigationController popViewControllerAnimated:YES];
    
    }
    

5

除了我之前的回答,我想展示另一种方法,直到几分钟前我才知道:使用取消转场而不是委托。

取消转场会以某种方式撤销将我们带到视图控制器的转场。 "某种方式"意味着您实际上不需要返回到先前的控制器,而是返回到先前的一个控制器。创建取消转场时,您将其与签名的目标连接

-(IBAction)actionName:(UIStoryboardSegue *)segue

在之前的一个视图控制器中。详情请查看这里:使用Xcode Storyboarding
调用操作的连线将包含源控制器,我们的情况是详细视图控制器。现在我们可以访问我们在其上定义的属性或方法。

@interface StateSelctionViewController : UITableViewController
@property (nonatomic, strong) NSString *selectedNation;
@property (nonatomic, strong, readonly) NSString *selectedState;
@end

我将selectedState设置为只读,以便清楚地表明它不能被设置,但在选择后应该被读取。我在类扩展中重新声明它为可读写。

@interface StateSelctionViewController ()
@property (nonatomic, strong, readwrite) NSString *selectedState;
@end

在故事板中,我创建了一个手动解缠的segue(如图Technical Note TN2298: Figure 2所示)。一旦选择行,我将设置selectedState并执行解缠segue。
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    self.selectedState =  stateDictionary[_selectedNation][indexPath.row];
    [self performSegueWithIdentifier:@"unwind" sender:self];
}

这将在主视图控制器中执行连接的操作。
-(void)returned:(UIStoryboardSegue *)sender
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
    [self.statesDictionray setObject:[sender.sourceViewController selectedState]
                              forKey:[sender.sourceViewController selectedNation]];
    [self.tableView reloadData];
}

我创建了一个样例代码:https://github.com/vikingosegundo/StateSelectionUnwind

谢谢,两个都对我有用。我看到你正在使用字典来存储状态。如果我在状态视图控制器中添加一个搜索栏,我应该能够搜索可用的选项,对吗? - GOAT
你现在使用的是哪个版本:委托还是this? - vikingosegundo
我正在使用委托 @vikingosegundo - GOAT
@EricOboite: 看看委托示例的新版本。它包含了基本的过滤功能。 - vikingosegundo
谢谢,这很有效!你能看一下我的最近的帖子http://stackoverflow.com/q/19042726/1568886吗?我需要为此子类化UiTableViewCell吗?@vikingosegundo - GOAT

1

扩展Vikingosegundo的建议:

当您的第一个视图控制器segue到第二个视图控制器时,实现prepareForSegue方法。

给第二个视图控制器添加一个符合parentVC协议的委托属性。

在parentVC协议中定义方法,让您通知委托当前选择的表格视图单元格。

在第一个视图控制器的prepareForSegue方法中,将自己设置为第二个视图控制器的委托。

当用户在第二个视图控制器中更改单元格时,使用委托属性通知父视图控制器。

我在github上有一个示例应用程序,说明了这种精确设置。我的设置是使用父/子视图控制器和嵌入式segue,但您可以对模态呈现、导航控制器基于导航或各种其他应用程序结构使用相同的方法。

该存储库的名称完全无用,名为“test”。您可以通过https://github.com/DuncanMC/test访问它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接