你如何将数据从 ViewController 传递到包含单独 ViewController 的 PageViewController,然后这些 ViewController 将使用这些数据?

Posted

技术标签:

【中文标题】你如何将数据从 ViewController 传递到包含单独 ViewController 的 PageViewController,然后这些 ViewController 将使用这些数据?【英文标题】:How do you pass data from a ViewController to a PageViewController containing separate ViewControllers which will then use this data? 【发布时间】:2015-06-15 17:14:19 【问题描述】:

我基本上有一个根 ViewController,我想将它传递到通过 PageViewController 连接的 ViewControllers 集合(所有不同的类本身)。

目前,我在根 ViewController 中设置了一个 prepareforsegue 来传递数据。然后我在 PageViewController 中声明了变量,并试图弄清楚如何将数据传递到 ViewControllers。

我目前只是在做一个简单的 Hello World 测试,所以我的代码有点简单。这是我的 RootViewController,我已将其传递到 PageViewController(并因此传递到连接到 PageViewController 的后续 VC):

class RootViewController: UIViewController 

    override func viewDidLoad() 
        super.viewDidLoad()
    
    var hello: String! = "Hello World!"
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) 
        if (segue.identifier == "testSegue")

            var svc = segue.destinationViewController as! PageViewController;

            svc.datapassed = self.hello

        
    

我的 PageView 控制器有点复杂。我正在使用情节提要 ID 方法,因为我希望 pageviewcontroller 显示不同类的视图控制器,而不是显示一个视图控制器模板和不同图像内容的大量教程......

    class PageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate 

        var datapassed: String!

        var index = 0
        var identifiers: NSArray = ["FirstNavigationController", "SecondNavigationController"]

        override func viewDidLoad() 
            super.viewDidLoad()
            setupPageControl()
            self.dataSource = self
            self.delegate = self

            let startingViewController = self.viewControllerAtIndex(self.index)
            let viewControllers: NSArray = [startingViewController]
            self.setViewControllers(viewControllers as [AnyObject], direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)

            // Do any additional setup after loading the view.
        

        func viewControllerAtIndex(index: Int) -> UIViewController! 
            if index == 0 

                return self.storyboard!.instantiateViewControllerWithIdentifier("FirstNavigationController") as! UIViewController

            
            if index == 1 

                return self.storyboard!.instantiateViewControllerWithIdentifier("SecondNavigationController") as! UIViewController
            

            return nil
        

        func pageViewController(pageViewController: UIPageViewController!, viewControllerAfterViewController viewController: UIViewController!) -> UIViewController! 

            let identifier = viewController.restorationIdentifier
            let index = self.identifiers.indexOfObject(identifier!)
            if index == identifiers.count - 1 

                return nil
            

            self.index = self.index + 1
            return self.viewControllerAtIndex(self.index)

        

        func pageViewController(pageViewController: UIPageViewController!, viewControllerBeforeViewController viewController: UIViewController!) -> UIViewController! 

            let identifier = viewController.restorationIdentifier
            let index = self.identifiers.indexOfObject(identifier!)
            if index == 0 

                return nil
            
            self.index = self.index - 1
            return self.viewControllerAtIndex(self.index)

        

        private func setupPageControl() 
            let appearance = UIPageControl.appearance()
            appearance.pageIndicatorTintColor = UIColor.grayColor()
            appearance.currentPageIndicatorTintColor = UIColor.whiteColor()

        

        func presentationCountForPageViewController(pageViewController: UIPageViewController!) -> Int 
            return self.identifiers.count
        

        func presentationIndexForPageViewController(pageViewController: UIPageViewController!) -> Int 
            return 0
        

    

最后,我只是想让第一个 ViewController 连接到 pageviewcontroller 以显示来自传递的变量 datapassed 的文本。

    class FirstViewController: UIViewController 

        @IBOutlet weak var helloLabel: UILabel!
        override func viewDidLoad() 
            super.viewDidLoad()
            helloLabel.text = datapassed
            // Do any additional setup after loading the view.
        
    

编辑: 可能的解决方案和最终代码:

    class RootViewController: UIViewController 

        override func viewDidLoad() 
            super.viewDidLoad()

        

        var carinfos: String! = "Hello World"
        override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) 
            if let svc = segue.destinationViewController as? PageViewController
                where segue.identifier == "testSegue" 
                    svc.dataPassed = self.carinfos
            
        
    

class PageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate 

    var dataPassed: String? 
        didSet 
            self.updateCurrentViewController()
        
    

    var index = 0
    var identifiers: NSArray = ["FirstNavigationController", "SecondNavigationController"]


    override func viewDidLoad() 
        super.viewDidLoad()
        self.dataSource = self
        self.delegate = self

        let startingViewController = self.viewControllerAtIndex(self.index)
        let viewControllers: NSArray = [startingViewController]
        self.setViewControllers(viewControllers as [AnyObject], direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)

    

    func updateCurrentViewController() 

        if let firstViewController = self.viewControllerAtIndex(self.index) as? FirstViewController, let data = self.dataPassed 
            firstViewController.dataPassed = data
        
    


    func pageViewController(pageViewController: UIPageViewController!, viewControllerAfterViewController viewController: UIViewController!) -> UIViewController! 

        let identifier = viewController.restorationIdentifier
        let index = self.identifiers.indexOfObject(identifier!)
        if index == identifiers.count - 1 

            return nil
        
        self.index = self.index + 1
        return self.viewControllerAtIndex(self.index)

    

    func pageViewController(pageViewController: UIPageViewController!, viewControllerBeforeViewController viewController: UIViewController!) -> UIViewController! 

        let identifier = viewController.restorationIdentifier
        let index = self.identifiers.indexOfObject(identifier!)

        if index == 0 

            return nil
        

        self.index = self.index - 1
        let viewController = self.viewControllerAtIndex(self.index)
        self.updateCurrentViewController()

        return viewController
    


    func viewControllerAtIndex(index: Int) -> UIViewController! 
        if index == 0 
            return self.storyboard!.instantiateViewControllerWithIdentifier("FirstNavigationController") as! UIViewController
        
        if index == 1 
            return self.storyboard!.instantiateViewControllerWithIdentifier("SecondNavigationController") as! UIViewController
        
        return nil
    

    func presentationCountForPageViewController(pageViewController: UIPageViewController!) -> Int 
        return self.identifiers.count
    

    func presentationIndexForPageViewController(pageViewController: UIPageViewController!) -> Int 
        return 0
    




class FirstViewController: UIViewController 
    var dataPassed: String?

    @IBOutlet weak var firstLabelTest: UILabel!
    @IBOutlet weak var firstLabel: UILabel!

    override func viewDidLoad() 
        super.viewDidLoad()
        println(dataPassed)
        firstLabel.text = "Hello, this is First"
        self.populateData()
    

    func populateData() 
        if let data = self.dataPassed 
            self.firstLabelTest.text = self.dataPassed
        
    


【问题讨论】:

【参考方案1】:

您可以简单地将其传递给视图控制器结构以使其正常工作,尽管这并不是一个深思熟虑的设计。为此,首先,确保您使用if let 绑定和有条件的向下转换 (as?) 正确地转换了 destinationViewController。您还可以使用where 子句将比较与segue 的identifier 结合起来。然后,您将拥有设置数据的对象。

FirstViewController 中,使用属性观察器在设置dataPassed 变量时更新标签,并在viewDidLoad 上更新它。

此外,您的 hello 属性不应是隐式展开的类型,因此您可以从声明中删除 !

class FirstViewController : UIViewController 

    @IBOutlet weak var helloLabel: UILabel!

    var dataPassed: String?

    override func viewDidLoad() 
        super.viewDidLoad()
        self.populateData()
    

    func populateData() 
        if let data = self.dataPassed 
            self.helloLabel.text = self.dataPassed
        
    



class PageViewController : UIPageViewController 

    var index = 0
    var identifiers: NSArray = ["FirstNavigationController", "SecondNavigationController"]

    var dataPassed: String? 
        didSet 
            self.updateCurrentViewController()
        
    

    func pageViewController(pageViewController: UIPageViewController!, viewControllerBeforeViewController viewController: UIViewController!) -> UIViewController! 

        let identifier = viewController.restorationIdentifier
        let index = self.identifiers.indexOfObject(identifier!)
        if index == 0 

            return nil
        
        self.index = self.index - 1
        let viewController = self.viewControllerAtIndex(self.index)

        self.updateCurrentViewController()

        return viewController
    

    func updateCurrentViewController() 

        if let firstViewController = self.viewControllerAtIndex(self.index) as? FirstViewController, let data = self.dataPassed 
            firstViewController.dataPassed = data
        
    

    func viewControllerAtIndex(index: Int) -> UIViewController! 
        // Create your VC as in the project template
        return nil
    


class RootViewController : UIViewController 

    var hello: String = "Hello World!"

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) 
        super.prepareForSegue( segue, sender: sender )
        if let svc = segue.destinationViewController as? PageViewController
            where segue.identifier == "testSegue" 
                svc.dataPassed = self.hello
        
    

【讨论】:

感谢您的回复。我想知道当您在 FirstViewController 中声明 dataPassed 时 didset 方法做了什么。此外,该行实际上是如何从 RootViewController 提取数据传递的,因为在情节提要上,segue 实际上是从 RootView 到 PageViewController? 对不起,我误解了你的结构,答案已更新。 啊。我觉得我很接近。我摆弄了几个小时的代码,但我无法让数据通过。该项目构建没有任何错误。但是,只是 dataPassed 在 FirstViewController 中不断返回 nil。我已经从上面更新了我的代码,我很确定我没有犯错,但不太确定。【参考方案2】:

根据您的应用程序的需求和其他结构,您还可以使用响应者链向层次结构中的任何视图控制器提供数据。

那么就这么简单:

class FirstViewController : UIViewController 

    @IBOutlet weak var helloLabel: UILabel!

    var dataPassed: String? 
        didSet 
            if let data = self.dataPassed 
                self.helloLabel.text = data
            
        
    

    override func viewWillAppear(animated: Bool) 
        super.viewWillAppear(animated)

        if let dataSource = self.nextResponder()?.targetForAction( "hello", withSender: self ) as? RootViewController 
            self.dataPassed = dataSource.hello
        
    



class RootViewController : UIViewController 

    var hello: String = "Hello World!"


【讨论】:

【参考方案3】:

swift3 你可以这样做 在您嵌入 pageviewcontroller 的主视图中,您可以使用带有标识符的 segue

override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
        if segue.identifier=="challengepostssegue"
         let destination=segue.destination as! PageMainController
            destination.challengeId=challengId
        
    

在PageMainController中声明一个变量可选类型

var challengeId:String?

【讨论】:

以上是关于你如何将数据从 ViewController 传递到包含单独 ViewController 的 PageViewController,然后这些 ViewController 将使用这些数据?的主要内容,如果未能解决你的问题,请参考以下文章

如何将数据从 AppDelegate 传递到 ViewController?

教程/示例:如何将数据从 ViewController 传递到另一个 XCODE [关闭]

如何将数据库从 AppDelegate 传递到 ViewController

如何将数据从可解码模型传递或实现到 ViewController?

如何将变量从 ViewController 类传递给其他结构?

将数据从 ViewController 传递到 NSObject