以编程方式创建序列


202

我有一个共同点UIViewController,就是我所有的UIViewsControllers扩展都可以重用一些共同的操作。

我想在此“公用”上建立一个序列,UIViewController以便其他所有UIViewControllers继承。

我正在尝试找出如何以编程方式进行操作。

我想这个问题还可能是我如何在不进入故事板的情况下segue为我的所有对象设置一个UIViewControllers并手工完成。

Answers:


169

根据定义,segue不能真正独立于故事板而存在。它甚至以类的名称存在:UIStoryboardSegue。您无需以编程方式创建剧集-情节提要运行时会为您创建它们。通常performSegueWithIdentifier:,您可以调用视图控制器的代码,但这取决于已经在情节提要中设置了segue进行引用。

我想您在问的是,如何在公共视图控制器(基类)中创建一个方法,该方法将过渡到新的视图控制器,并被所有派生类继承。您可以通过在基类视图控制器中创建一个像这样的方法来做到这一点:

- (IBAction)pushMyNewViewController
{
    MyNewViewController *myNewVC = [[MyNewViewController alloc] init];

    // do any setup you need for myNewVC

    [self presentModalViewController:myNewVC animated:YES];
}

然后在您的派生类中,当单击适当的按钮或选择了表行时,调用该方法。


4
谢谢。可惜我们不能以编程方式做到这一点。它将真正提高源代码的质量(重复总是越少越好)。我同意你的建议。
Tiago Veloso 2012年

2
@jonkroll是否可以从switch语句调用/执行segue,即基于我拥有的索引?
codejunkie 2012年

5
@codejunkie:是的,您可以这样做。您将使用为此UIViewController命名的方法performSegueWithIdentifier:sender:
jonkroll 2012年

2
我一直在以编程方式创建和执行segue(请参阅我的答案)。如果您的答案正确,那么我的代码有什么问题吗?
Jean-Philippe Pellet

13
更新为iOS 6+:UIViewpresentModalViewController:animated:已被弃用。从文档开始 - (在iOS 6.0中已弃用。请使用presentViewController:animated:completion:代替。)
用户

346

我以为我会增加另一种可能性。您可以做的一件事是,可以使用未附加到动作的segue在情节提要中连接两个场景,然后以编程方式在视图控制器中触发segue。为此,您必须从情节提要场景的情节提要场景底部的文件所有者图标中拖动,然后向右拖动至目标场景。我会扔一张图片以帮助解释。

在此处输入图片说明

弹出窗口将显示“ Manual Segue”。我选择了Push作为类型。点击小方块,并确保您位于属性检查器中。给它一个标识符,您将在代码中使用它来引用它。

在此处输入图片说明

好的,接下来我将使用程序化的条形按钮项进行搜索。在viewDidLoad或其他地方,我将使用以下代码在导航栏上创建一个按钮项:

UIBarButtonItem *buttonizeButton = [[UIBarButtonItem alloc] initWithTitle:@"Buttonize"
                                                                    style:UIBarButtonItemStyleDone
                                                                   target:self
                                                                   action:@selector(buttonizeButtonTap:)];
self.navigationItem.rightBarButtonItems = @[buttonizeButton];

好的,请注意选择器是buttonizeButtonTap:。因此,为该按钮编写一个void方法,并在该方法内调用segue,如下所示:

-(void)buttonizeButtonTap:(id)sender{
    [self performSegueWithIdentifier:@"Associate" sender:sender];
    }

调用prepareForSegue时,需要sender参数来标识按钮。prepareForSegue是一种框架方法,您可以在其中实例化场景并将其执行工作所需的任何值传递给它。这是我的方法:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"Associate"])
    {
        TranslationQuizAssociateVC *translationQuizAssociateVC = [segue destinationViewController];
        translationQuizAssociateVC.nodeID = self.nodeID; //--pass nodeID from ViewNodeViewController
        translationQuizAssociateVC.contentID = self.contentID;
        translationQuizAssociateVC.index = self.index;
        translationQuizAssociateVC.content = self.content;
    }
}

好的,只需对其进行测试即可。希望对您有帮助。


@MichaelRowe这如何消除对争执的需要?在我看来,你还是要拖和故事板拖放到目标控制器..
aherrick

@MichaelRowe这并不能消除进行测试的必要性。这样做是让您在用代码而不是在界面生成器中构建的视图控制器之间进行选择。
马修

@Matt实际上只是让我完全重新考虑如何设置应用程序...在完全重写了所有UI之后,我不再使用任何按钮。.–
Michael Rowe

@cocoanut我得到的错误是“应用程序试图把模态启动控制”任何帮助,对此..
巴拉

1
不建议使用手动Segue“推送”,请使用“显示”。该答案有更多详细信息。@smileBot,请更新答案。
NAbbas

81

我一直在使用此代码实例化我的自定义segue子类并以编程方式运行它。它似乎有效。这有什么问题吗?我很困惑,阅读所有其他回答都说无法完成。

UIViewController *toViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"OtherViewControllerId"];
MyCustomSegue *segue = [[MyCustomSegue alloc] initWithIdentifier:@"" source:self destination:toViewController];
[self prepareForSegue:segue sender:sender];
[segue perform];

4
MyCustomSegue中有什么?
Victor Engel 2013年

3
这是的自定义子类UIStoryboardSegue
Jean-Philippe Pellet

7
@MarkAmery很多人(包括我)避免使用情节提要。它们很难合并,也没有编译时检查来确保我传递给的ID performSegueWithIdentifier:确实在情节提要中定义。我自己创建segue可以避免所有问题。
Jean-Philippe Pellet

3
我同意让·菲利普的观点。管理情节提要是一个麻烦。当然,通过单击几个视图并在此处添加一个序列,然后在其中添加序列是很容易的,但是当您有3个开发人员都对XML进行定义时,使用16个以XML定义的序列管理6个视图是很糟糕的。无论如何,关键是:代码让您可以控制,xcode生成的xml没有。
Krystian

3
我在iOS7的[segue perform]中看到崩溃,不确定是否有人遇到这种情况。
Eric Chen

45

猜猜这已经被回答并接受了,但是我只想添加一些细节。

我要解决的一个问题是我将登录视图显示为第一个屏幕,然后在登录正确的情况下想找到该应用程序。我创建了从登录视图控制器到根视图控制器的segue,并为其指定了诸如“ myidentifier”的标识符。

然后在检查所有登录代码后,如果登录正确,我会打电话给

[self performSegueWithIdentifier: @"myidentifier" sender: self];

我最大的误解是我试图将按钮设置为按钮,并在发现后立即中断。


4
正如我写的另一条评论:我一直在以编程方式创建和执行自定义搜索(请参阅我的答案)。
Jean-Philippe Pellet

32

您必须将代码链接到UIStoryboard所使用的。确保你进入YourViewController在你的UIStoryboard,点击它周围的边框,然后将其设置identifier字段添加到NSString您在代码中调用。

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" 
                                                     bundle:nil];
YourViewController *yourViewController = 
 (YourViewController *)
  [storyboard instantiateViewControllerWithIdentifier:@"yourViewControllerID"];
[self.navigationController pushViewController:yourViewController animated:YES];

1
我明白了,但是如果要呈现的viewController嵌入情节提要中的NavigationController中怎么办?据我所知,我可以初始化一个NavigationController来嵌入它,但在情节提要中,我已经为需要显示的视图设置了推推设置。
jhilgert00 2012年

1
你能详细说明一下吗?我认为这是我遇到的问题,但似乎找不到如何/在何处执行此操作……
jesses.co.tt

1
甚至这个解决方案都是正确的,它是关于避免任何干扰的问题,但是问题是关于干扰的问题。这样,您就可以在情节提要中在没有场景的情况下连接或在两个场景之间进行过渡。
BootMaker '16

16

对于情节提要中的控制器。

jhilgert00这是您要找的东西吗?

-(IBAction)nav_goHome:(id)sender {
UIViewController *myController = [self.storyboard instantiateViewControllerWithIdentifier:@"HomeController"];
[self.navigationController pushViewController: myController animated:YES];

}

要么...

[self performSegueWithIdentifier:@"loginMainSegue" sender:self];


3

我想澄清一下...

一个常见的误解(实际上是我一段时间以来的误解)是该prepareForSegue:sender:方法触发了情节提要剧集。它不是。将执行情节提要剧集,无论您是否已prepareForSegue:sender:为该视图控制器实现了方法(从视图控制器出发)。

我从Paul Hegarty出色的iTunesU讲座中学到了这一点。我很抱歉,但是很遗憾,我不记得上哪个课。

如果您在情节提要中的两个视图控制器之间连接了Segue,但未实现prepareForSegue:sender:方法,则该Segue仍将Segue到目标视图控制器。但是,它将毫无准备地锁定该视图控制器。

希望这可以帮助。


3

情节提要Segues不能在情节提要之外创建。尽管有缺点,您仍需要将其连接起来。

UIStoryboardSegue参考明确指出:

您不能直接创建segue对象。相反,情节提要运行时必须在两个视图控制器之间执行segue时创建它们。如果需要,您仍然可以使用UIViewController的performSegueWithIdentifier:sender:方法以编程方式启动segue。您可能这样做是从以编程方式添加的源中启动序列,因此在Interface Builder中不可用。

您仍然可以通过编程方式告诉情节提要通过使用segue presentModalViewController:pushViewController:animated:调用来呈现一个视图控制器,但是您将需要一个情节提要实例。

您可以调用UIStoryboards类方法来获取一个命名的故事板,其中主包的包为nil。

storyboardWithName:bundle:


2

首先,假设您在情节提要中有两个不同的视图,并且想从一个屏幕导航到另一个屏幕,所以请按照以下步骤操作:

1)。使用类文件以及身份检查器中的情节提要ID定义所有视图。

2)。确保将导航控制器添加到第一个视图。在情节提要中选择它,然后选择“编辑器”>“嵌入”>“导航控制器”

3)。在您的第一堂课中,导入“ secondClass.h”

#import "ViewController.h
#import "secondController.h"

4)。在必须执行segue的IBAction中添加此命令

secondController *next=[self.storyboard instantiateViewControllerWithIdentifier:@"second"];
[self.navigationController pushViewController:next animated:YES];

5)。@"second"是secondview控制器类,情节提要ID。


self.storyboard应该是:UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
masipcat

@masipcat和故事板的名称可能取决于您如何设置Xcode项目,在我的例子中是“ Main.storyboard”,因此我使用了storyboardWithName:@"Main"
ammianus

@ sanket-chauhan如果您的第一个控制器未嵌入导航控制器中,则还可以使用[self showDetailViewController:next sender:self];[self showViewController:next sender:self];
ammianus

1

我进行了反向工程,并实现了UIStoryboard的segues的开源(重新)实现:https : //github.com/acoomans/Segway

使用该库,您可以以编程方式(没有任何情节提要)定义segue。

希望对您有所帮助。


0

实际上有几个问题:

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

没有标识符

如果还没有,请填写该标识符。

其次,当您从表视图推送到表视图时,您要调用initWithNibName来创建视图控制器。您确实要使用InstantiateViewControllerWithIdentifier。


0

这是以下代码的示例Creating a segue programmatically

class ViewController: UIViewController {
    ...
    // 1. Define the Segue
    private var commonSegue: UIStoryboardSegue!
    ...
    override func viewDidLoad() {
        ...
        // 2. Initialize the Segue
        self.commonSegue = UIStoryboardSegue(identifier: "CommonSegue", source: ..., destination: ...) {
            self.commonSegue.source.showDetailViewController(self.commonSegue.destination, sender: self)
        }
        ...
    }
    ...
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // 4. Prepare to perform the Segue
        if self.commonSegue == segue {
            ...
        }
        ...
    }
    ...
    func actionFunction() {
        // 3. Perform the Segue
        self.prepare(for: self.commonSegue, sender: self)
        self.commonSegue.perform()
    }
    ...
}

您正在self.prepare(for: self.commonSegue, sender: self)通过操作方法进行调用。那么if self.commonSegue == segue {...}prepare(for:sender)方法上进行比较有什么意义呢?
nayem '17

@nayem:在中prepare(for:sender:),您可以在显示目标视图控制器之前对其进行配置。当然您也可以在中进行actionFunction
jqgsninimo

@nayem:我这样做的原因是试图与其他segue的处理保持一致。
jqgsninimo
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.