如何使用 Swift 在 iOS 中以编程方式进行 segue

Posted

技术标签:

【中文标题】如何使用 Swift 在 iOS 中以编程方式进行 segue【英文标题】:How to segue programmatically in iOS using Swift 【发布时间】:2015-02-20 15:23:07 【问题描述】:

我正在创建一个使用 Facebook SDK 对用户进行身份验证的应用。我正在尝试将 facebook 逻辑合并到一个单独的类中。这是代码(为简单起见,已删除):

import Foundation

class FBManager 
    class func fbSessionStateChane(fbSession:FBSession!, fbSessionState:FBSessionState, error:NSError?)
        //... handling all session states
        FBRequestConnection.startForMeWithCompletionHandler  (conn: FBRequestConnection!, result: AnyObject!, error: NSError!) -> Void in
        
            println("Logged in user: \n\(result)");
        
            let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
            let loggedInView: UserViewController = storyboard.instantiateViewControllerWithIdentifier("loggedInView") as UserViewController
        
            loggedInView.result = result;
        
            //todo: segue to the next view???
        
    

我正在使用上面的类方法来检查会话状态的变化,它工作正常。

问:获得用户数据后,如何从这个自定义类中转到下一个视图?

为了清楚起见,我在情节提要上有一个带标识符的转场,我正在尝试找到一种方法来从不是视图控制器的类中执行转场

【问题讨论】:

喜欢performSegue:? 是的,但是代码不在viewController中,我怎样才能做到这一点? 好吧,在这种情况下,您应该将工作(转场)从您执行工作的对象委托给视图控制器(通过完成块或委托方法)。 获得非零布局异常 【参考方案1】:

如果您的 segue 存在于故事板中,并且您的两个视图之间有一个 segue 标识符,您可以使用以下方式以编程方式调用它:

performSegue(withIdentifier: "mySegueID", sender: nil)

对于旧版本:

performSegueWithIdentifier("mySegueID", sender: nil)

你也可以这样做:

presentViewController(nextViewController, animated: true, completion: nil)

或者如果您在导航控制器中:

self.navigationController?.pushViewController(nextViewController, animated: true)

【讨论】:

感谢您的回复,如何从不是视图的自定义类中调用 performSegueWithIdentifier? 如果我使用你的第二种方法。如何将数据传递给下一个视图? 您将使用 func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) 并设置属性。 注意在调用 performSequeWithIdentifer() 时,调用控制器中的 prepareForSeque() 实现将被调用,您可以在那里传递各种数据 - 实际上,prepareForSeque() 中接收到的 sender 参数很简单performSequeWithIdentifier() 中传递给 sender 参数的内容 如果故事板中不存在segue怎么办?例如,如果你想为 ViewController 本身创建一个 segue?【参考方案2】:

如果您的 segue 存在于故事板中,并且您的两个视图之间有一个 segue 标识符,您可以使用编程方式调用它

self.performSegueWithIdentifier("yourIdentifierInStoryboard", sender: self)

如果你在导航控制器中

let viewController = YourViewController(nibName: "YourViewController", bundle: nil)        
self.navigationController?.pushViewController(viewController, animated: true)

我会推荐你​​使用导航控制器的第二种方法。

【讨论】:

self.performSegue(withIdentifier: "yourIdentifierInStoryboard", sender: self)【参考方案3】:

您可以使用 NSNotification

在你的自定义类中添加一个 post 方法:

NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: nil)

在你的 ViewController 中添加一个观察者:

NSNotificationCenter.defaultCenter().addObserver(self, selector: "methodOFReceivedNotication:", name:"NotificationIdentifier", object: nil)

在你的 ViewController 中添加函数:

func methodOFReceivedNotication(notification: NSNotification)
    self.performSegueWithIdentifier("yourIdentifierInStoryboard", sender: self)

【讨论】:

请不要滥用这样的通知。使用委托并使视图控制器和您的类之间的连接显式。观察通知的控制流程几乎是不可能的,因为可能有多个订阅者,并且实例可以随意订阅/取消订阅。【参考方案4】:

你可以像这样使用segue:

self.performSegueWithIdentifier("push", sender: self)
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) 
    if segue.identifier == "push" 

    

【讨论】:

感谢回复,但是 performSegueWithIdentifier 是 viewController 方法,我的代码在外部类中运行【参考方案5】:

Swift 3 - 也适用于 SpriteKit

您可以使用 NSNotification

示例:

1.) 在情节提要中创建一个转场并将标识符命名为“转场”

2.) 在您要从中进行切换的 ViewController 中创建一个函数。

func goToDifferentView() 

    self.performSegue(withIdentifier: "segue", sender: self)


3.) 在您的 ViewController 的 ViewDidLoad() 中,您正在创建观察者。

NotificationCenter.default.addObserver(self, selector: #selector(goToDifferentView), name: "segue" as NSNotification.Name, object: nil)

更新 - 上次我使用它时,我不得不将 .addObserver 调用更改为以下代码以消除错误。

NotificationCenter.default.addObserver(self, selector: #selector(goToDifferentView), name: NSNotification.Name(rawValue: "segue"), object: nil)

4.) 在您要转场的 ViewController 或场景中,在您希望触发转场的任何位置添加 Post 方法。

NotificationCenter.default.post(name: "segue" as NSNotification.Name, object: nil)

更新 - 上次我使用它时,我不得不将 .post 调用更改为以下代码以消除错误。

NotificationCenter.default.post(NSNotification(name: NSNotification.Name(rawValue: "segue"), object: nil) as Notification)

【讨论】:

斯威夫特 3:NotificationCenter.default.addObserver(self, selector: #selector(goToDifferentView), name: NSNotification.Name(rawValue: "segue"), object: nil)【参考方案6】:

您想要做的事情对于单元测试非常重要。基本上你需要在视图控制器中创建一个小的本地函数。将函数命名为任何名称,只需包含 performSegueWithIndentifier

func localFunc() 
    println("we asked you to do it")
    performSegueWithIdentifier("doIt", sender: self)

接下来更改您的实用程序类 FBManager 以包含一个初始化程序,该初始化程序接受一个函数的参数和一个变量来保存执行 segue 的 ViewController 的函数。

public class UtilClass 

    var yourFunction : () -> ()

    init (someFunction: () -> ()) 
        self.yourFunction = someFunction
        println("initialized UtilClass")
    

    public convenience init() 
        func dummyLog () -> () 
            println("no action passed")
        
        self.init(dummyLog)
    

    public func doThatThing() -> () 
        // the facebook login function
        println("now execute passed function")
        self.yourFunction()
        println("did that thing")
    

(方便的 init 允许您在不执行 segue 的情况下在单元测试中使用它。)

最后,如果你有 //todo: 继续下一个视图???

self.yourFunction()

在您的单元测试中,您可以简单地调用它:

let f = UtilClass()
f.doThatThing()

其中 doThatThing 是您的 fbsessionstatechange,UtilClass 是 FBManager。

对于您的实际代码,只需将 localFunc(无括号)传递给 FBManager 类。

【讨论】:

【参考方案7】:

这对我有用。

首先,在身份检查器中为情节提要中的视图控制器提供情节提要 ID。然后使用以下示例代码(确保类、故事板名称和故事板 ID 与您使用的匹配):

let viewController:
UIViewController = UIStoryboard(
    name: "Main", bundle: nil
).instantiateViewControllerWithIdentifier("ViewController") as UIViewController
// .instantiatViewControllerWithIdentifier() returns AnyObject!
// this must be downcast to utilize it

self.presentViewController(viewController, animated: false, completion: nil)

更多详情见http://sketchytech.blogspot.com/2012/11/instantiate-view-controller-using.html 最好的祝福

【讨论】:

【参考方案8】:

上面已经有很好的答案了,我想在执行 segue 之前将重点放在准备工作上。

override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
        if segue.destination is YourDestinationVC 
            let vc = segue.destination as? YourDestinationVC
            // "label" and "friends" are part of destinationVC
            vc?.label = "someText"
            vc?.friends = ["John","Mike","Garry"]
        

一旦你完成了你想要传递给你的destinationVC的数据,然后在适当的地方执行你的segue。 您可以在 StoryBoard ID 字段的 StoryBoard Identity 检查器中设置“IdentifierOfDestinationVC”

performSegue(withIdentifier: "IdentifierOfDestinationVC", sender: nil)

【讨论】:

【参考方案9】:

你可以使用performSegueWithIdentifier函数来做这件事。

语法:

func performSegueWithIdentifier(identifier: String, sender: AnyObject?)

示例:

 performSegueWithIdentifier("homeScreenVC", sender: nil)

【讨论】:

【参考方案10】:

另一种选择是使用模态转场

第 1 步:转到情节提要,并为视图控制器提供一个情节提要 ID。您可以在右侧的 Identity Inspector 中找到更改情节提要 ID 的位置。 让我们调用storyboard ID ModalViewController

第 2 步:打开 'sender' 视图控制器(我们称之为 ViewController)并将此代码添加到其中

public class ViewController 
  override func viewDidLoad() 
    showModalView()
  

  func showModalView() 
    if let mvc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ModalViewController") as? ModalViewController 
      self.present(mvc, animated: true, completion: nil)
    
  

注意我们要打开的View Controller也叫ModalViewController

第 3 步:要关闭 ModalViewController,请将其添加到其中

public class ModalViewController 
   @IBAction func closeThisViewController(_ sender: Any?) 
      self.presentingViewController?.dismiss(animated: true, completion: nil)
   

【讨论】:

【参考方案11】:

这对我有用:

//Button method example
 @IBAction func LogOutPressed(_ sender: UIBarButtonItem) 

        do 
            try Auth.auth().signOut()
            navigationController?.popToRootViewController(animated: true)

         catch let signOutError as NSError 
          print ("Error signing out: %@", signOutError)
        


    

【讨论】:

以上是关于如何使用 Swift 在 iOS 中以编程方式进行 segue的主要内容,如果未能解决你的问题,请参考以下文章

如何在ios swift中以编程方式创建自动布局等宽度约束?

在 iOS Swift 3 中以编程方式添加 Web 视图时如何在 UIWebView 中获取响应状态代码?

如何在 ios swift 中以编程方式将情节提要视图控制器加载到标签栏控制器中?

在 iOS 10 + Swift 3 中以编程方式在我的 WKWebView 上方添加 UILabel

如何在 Swift 中以编程方式创建新的 UIViewController

我可以在 Swift 5 和 IOS 12 中以编程方式更改 iOS 屏幕壁纸吗