【问题标题】:ipad uisplitview: passing data from masterviewcontroller to a uiviewcontroller (redirected via segue)ipad uisplitview:将数据从 masterviewcontroller 传递到 uiviewcontroller(通过 segue 重定向)
【发布时间】:2013-02-03 01:45:09
【问题描述】:

我是 iOS 编程的新手,所以我想从头开始制作这个东西,以便能够理解整个东西是如何工作的。因此,我没有使用主详细信息模板,而是从头开始这样做。

在主视图和详细视图之间传递数据方面,我遇到了巨大的障碍。目前,每当我点击主视图的项目时,它都会在详细视图控制器上查找第一个视图,我们称之为mainswitchviewcontroller。这是第一个ViewController 通过segue 连接到UINavigationController 的详细控制器部分(请参阅下图)。

这发生在登录后显示viewcontroller,我希望用户在访问整个应用程序之前选择一个选项。这将引导他们到达流程的最后一个ViewController(请参阅下图 - 红色圆圈)。

现在我要做的是:

@interface MasterListViewController : UITableViewController{
}

@property (nonatomic) int matNum;
@property (strong, nonatomic) DetailStaffMainContentViewController *detailViewController;
@end

:
:

@implementation MasterListViewController
@synthesize matNum;
:
:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

    for(UIViewController *vc in self.splitViewController.viewControllers){
        NSLog(@"%@)", vc.title);
    }

    self.detailViewController.teststring = @"gronk";
}

这是我的 detailViewController(我要访问的那个)

@implementation DetailStaffMainContentViewController
@synthesize tableView;
@synthesize teststring;
@synthesize lblOutput;

现在在选择行时,我分配了teststring,我想用它来填充控制器上的标签。这就是我所做的。

我的问题是:

  1. 我遇到了一个错误。想知道我做错了什么吗?

    [MainSwitchBoardViewController setTeststring:]: unrecognized selector
    sent to instance 0x7572190
    
  2. 这是一种推荐的数据传递方式吗?还是我应该坚持使用通知中心?

想法?

编辑 只是为了让您了解应用程序的流程:

  1. 用户登录(如果用户名不存在,会弹出浮动viewcontroller强制用户登录。

  2. 一旦用户登录,弹出窗口就会消失,然后询问用户在当前会话中使用什么类型的角色(例如,职员或战士)。

  3. 如果用户选择战士,则将用户推到顶部 VC 如果用户选择人员,则将用户推到底部 VC(集合控制器)

  4. 对于员工:目前我正在使用这个 [self perfermSegueWithIdentifier:sender:self] 推到最后一个 VC

    一旦用户看到最后一个 VC (DetailsS​​taffView),我希望这是用户进行交易的主要详细信息视图。还有几个弹出窗口? (或者可能需要为特定交易添加另一个推送到另一个 VC)。但最终我不希望用户访问第一个 Viewcontroller (MasterSwitchBoard)

编辑 2 这是登录后控制第一个VC的主交换机类。

@interface MainSwitchBoardViewController : UIViewController{

}

@property (strong, nonatomic) IBOutlet UILabel *txtLabel;
- (IBAction)btnStaff:(id)sender;
- (IBAction)btnAdmin:(id)sender;

@end

这是 atm 自动推送到最后一个 VC 的集合 VC。一开始我在使用通知,但似乎没有必要,所以我把它拿出来了。

@interface MatListCollectionViewController ()

@end

@implementation MatListCollectionViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    [self performSegueWithIdentifier:@"SeguePushToStaffDetailFromMats" sender:self];
}

然后是细节人员

@interface DetailStaffMainContentViewController : UIViewController{

}

@property (strong, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic, retain) IBOutlet UILabel *lblOutput;
@property (nonatomic, retain) NSString *teststring;

@end


    @implementation DetailStaffMainContentViewController
    @synthesize tableView;
    @synthesize teststring;
    @synthesize lblOutput;

【问题讨论】:

    标签: xcode ipad uitableview uiviewcontroller uisplitviewcontroller


    【解决方案1】:

    我将按相反的顺序处理这些问题:

    这是一种推荐的数据传递方式吗?还是我应该坚持使用通知中心?

    理论上你可以使用通知中心,但在这种情况下我不会。就个人而言,我只在以下情况下使用NSNotificationCenter

    • 我正在执行异步进程,它无法合理地了解视图控制器的状态(例如,我有一些后台任务正在从服务器更新一些耗时的数据,而用户可能已经导航当我准备好通知视图控制器更新完成时,到应用程序中的几乎任何地方);和/或

    • 我可能有多个对象要通知某个事件。

    这些条件都不适用于这里。当然你可以使用NSNotificationCenter,但这应该是不必要的。显式设置属性通常更可取。

    我遇到了一个错误。想知道我做错了什么吗?

    很遗憾,根据您迄今为止提供的证据,很难说。但是根据您的代码和 cmets,我无法协调一些事情:

    • 您已将 detailViewController 声明为 DetailStaffMainContentViewController(这是您为其合成了 teststring 访问器的类);

    • 但是您的错误消息表明detailViewController 显然是MainSwitchBoardViewController 对象(它不理解setTeststring 访问器方法);和

    • 你没有向我们展示你是如何设置detailViewController的,所以在这里很难说你哪里出错了。

    就个人而言,在这种情况下,我总是不愿定义属性来维护指向视图控制器的指针。我通常倾向于询问UISplitViewController detail 拆分中的内容。因此,在我的主视图控制器中,我没有一个类属性/ivar,而是有一个类似的方法:

    - (UIViewController *)detailViewController
    {
        return [[self.splitViewController.viewControllers lastObject] topViewController];
    }
    

    这基本上是说“从我的拆分视图控制器数组viewControllers(详细拆分)中获取最后一个对象,并且因为我(个人)总是在该详细拆分中使用导航控制器,所以让我们使用topViewController 来获取一个指向我的子类UIViewController 的指针,它在那个细节拆分中(嵌入在导航控制器中)。

    然后我让didSelectRowAtIndexPath 检查该视图控制器是否是我所期望的。如果没有,我继续使用它(并让prepareSegue 将我想要的数据传递给该控制器)。

    因此,例如,考虑这个故事板:

    这里,“A”是我的默认细节控制器。 “B”可能是我可能用“A”替换的一些随机场景。 “C”是我真正的细节视图控制器,我可以在其中看到我从主视图控制器的表视图中选择的项目的详细信息。因此,我的主视图控制器的didSelectRowAtIndexPath 可能看起来像:

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
        UIViewController *controller = [self detailViewController];
    
        if (![controller isKindOfClass:[DetailCViewController class]])
        {
            // if I'm not already showing "C" in my detail split, then let's segue to it
    
            [self performSegueWithIdentifier:@"GoToC" sender:self];
        }
        else
        {
            // if I'm already showing "C" in my detail split, let's just set the item of data I want to pass to it
    
            DetailCViewController *cController = (DetailCViewController *)controller;
    
            cController.detailItem = self.objects[indexPath.row];
        }
    
        // I have a method I call to make sure that the popover menu for the master view
        // controller disappears (in case it popped up since I was in portrait mode) and
        // adds the master view controller button to the navigation bar if I need it.
    
        [self removePopoverAndAddNavigationButton];
    }
    

    如果我需要转至“C”,我还让我的 `prepareSegue 根据需要传递 detailItem:

    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    {
        if ([segue.identifier isEqualToString:@"GoToC"])
        {
            DetailCViewController *cController = (DetailCViewController *)[segue.destinationViewController topViewController];
    
            cController.detailItem = self.objects[[[self.tableView indexPathForSelectedRow] row]];
        }
    }
    

    正如我所说,试图弄清楚为什么你的 detailViewController 有错误类型的对象很难说,但这是我可以解决此类问题的方法。

    【讨论】:

    • 嗨,Rob,感谢您抽出宝贵时间回答我的问题!它确实帮助我理解了一些事情。是的,这就是我在错误中注意到的,即使它被推送到最后一个 VC,它仍然会认为它是主交换机(第一个 VC 连接到 UiNav)。如果您想知道,视图会通过 segue 从主开关推送到集合视图(第二个 UIView),然后通过 [self perfermSegueWithIdentifier:sender:self] 再次推送到最后一个视图。这对我来说没有意义。推动 VC 是否只是将 VC 置于主要细节之上?而不是替换它?
    • @gdubs 是的,导航控制器使用“堆栈”隐喻,其中每个“推”在其他顶部添加一个视图控制器,每个“弹出”从堆栈顶部移除(种类就像您的网络浏览器上的“返回”按钮)。这通常是一种非常有用的技术,因此您可以准确地回到您在上一个 VC 中的位置。但是,在处理UISplitViewCongtroller 时,您还有一个“替换”segue 的附加选项,正如其名称所暗示的那样,它不会将先前的控制器保存在那个特定的“拆分”中(即主拆分或细节拆分) .
    • 所以我更新了这个问题。现在我想知道我是否应该完全更换那个主交换机,以便它完全消失。因为我不想在用户到达最后一个 VC(detailstaffview)之后访问它。另外,您认为我应该删除那个主交换机并将其与登录 vc(浮动一个)连接,因为它们就像配置步骤,然后任何人都可以真正使用该应用程序..
    • 我的错,也更新了代码。同样对于您的答案>> - (UIViewController *)detailViewController .. 这将是我需要在接口文件上声明的方法吗?还是我只是放置一个新属性,然后让此方法填充此类属性?
    • @gdubs 让我们continue this discussion in chat 如果您愿意。不鼓励在 cmets 中进行扩展讨论,但聊天是一个很好的场所。
    【解决方案2】:

    也许你应该先看看一些不错的movies from the last WWDC,他们在其中描述了 Storyboard Segues。

    在您提供的代码中,没有任何关于 segue 的内容。请务必通过 IB 或以编程方式通过 [self performSegueWithIdentifier:] 使用 segue。 See Apple Docs

    然后你可以在你的视图控制器中提供额外的操作:

    • [view shouldPerformSegueWithIdentifier:sender:]
    • [view prepareForSegue:sender:]

    第一个决定是否执行转场。第二个是在 segue 执行之前执行的。在第二个操作中,您可以向destinationViewController 提供信息。

    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    {
        if([segue.identifier isEqualToString:@"showIssuesByProject"]){
            if (_searchActive) {
                ((IssueListViewController *)segue.destinationViewController).project = [_filteredProjects projectAtIndex:[self.tableView indexPathForSelectedRow].row];
            } else {
                ((IssueListViewController *)segue.destinationViewController).project = [_projects projectAtIndex:[self.tableView indexPathForSelectedRow].row];
            }
        }
        if ([segue.identifier isEqualToString:@"showIssuesByFilter"]) {
            ((IssueListViewController *)segue.destinationViewController).filter = [_filters filterAtIndex:[self.tableView indexPathForSelectedRow].row];
        }
    }
    

    注意:UISplitViewControll.viewControllers 只有两个控制器:主控制器和细节控制器。

    【讨论】:

    • 哦,我的错,我跳过了 segue 的推动。它实际上发生在那个“黑色视图控制器”上,它是一个将它推到那里的集合视图控制器。我跳过了它,因为我想确保数据在 master 和 detail 之间传递。并且流程的那部分不需要与最终视图控制器取得联系。崩溃实际发生在这一行 self.detailViewController.teststring = @"gronk";
    • 错误信息表示self.destinationViewController没有setTeststring方法。通常这意味着如果以默认方式合成,则控制器没有属性teststring。正如我在您的代码中看到的,一切都应该没问题,所以唯一可用的错误场景是:self.detailViewController 不是声明的 DetailStaffMainContentViewController。你应该先在调试模式下检查这个
    • @gdubs 如果您将“细节”拆分推到新场景,您可以绕过导航控制器(因为您已经有一个)。如果您要替换“详细”拆分,您可能希望从导航控制器开始替换。 (通常使用拆分视图,导航栏中有一个左按钮,显示主视图控制器的弹出窗口,因此保留导航栏通常很有用。)显然,做任何你想做的事,但我通常确保我在细节拆分中保留一个导航栏以使其更容易。
    • @Rob 是的,这就是我想要做的。顺便说一句,我更新了这个问题,让您了解我希望流程如何工作。我目前正在尝试使用 wwdc 102 会话来理解拆分视图。看起来这就是你所推荐的,用一组拥有自己 UINav 的新视图替换它?要么我走上正轨,要么完全迷路。大声笑
    猜你喜欢
    • 2017-02-20
    • 2014-11-30
    • 2016-05-30
    • 1970-01-01
    • 2015-05-19
    • 2020-10-01
    • 2018-04-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多