从另一个Swift视图控制器访问视图控制器实例

31

我正在尝试将一个视图控制器中的文本字段数据传输到另一个视图控制器中的标签。

我该如何从另一个视图控制器的代码中调用视图控制器实例?我正在使用故事板,因此我没有在代码中创建视图控制器的实例?这些实例是否会自动创建?它们的名称是什么?

谢谢您的帮助!


在ViewController A中,您创建了ViewController B。现在您可以访问ViewController B,只需设置一个属性或发送消息到ViewController B即可。 现在,您可以将ViewController B推入导航控制器。 - John
3个回答

21

1. 如果包含textfield的视图控制器可以通过segue调用包含label的视图控制器...

在您的项目中添加一个新的Cocoa Touch类文件,命名为FirstViewController,并将以下代码设置在其中:

import UIKit

class FirstViewController: UIViewController {
    
    @IBOutlet weak var textField: UITextField! // FIXME: link this to the UITextField in the Storyboard!!!
    
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        let controller = segue.destinationViewController as! SecondViewController
        controller.text = textField.text
    }
    
}
在您的项目中添加一个新的Cocoa Touch类文件,将其命名为SecondViewController并在其中设置以下代码。
import UIKit

class SecondViewController: UIViewController {
    
    var text: String?
    @IBOutlet weak var label: UILabel! // FIXME: link this to the UILabel in the Storyboard!!!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        label.text = text
    }
    
}
在Storyboard中,将第一个视图控制器嵌入UINavigationController。使用UIButtonUIBarButtonItem将第一个视图控制器链接到第二个视图控制器。将第一个视图控制器的名称设置为FirstViewController,第二个视图控制器的名称设置为SecondViewController。在第一个视图控制器中创建一个UITextField。在第二个视图控制器中创建一个UILabel。将文本字段和标签分别链接到FirstViewControllerSecondViewController中的相应声明。
如果包含标签的视图控制器可以调用(通过segue)包含文本字段的视图控制器,则这是一个完美的协议/委托案例。你可以在StackOverflow上找到大量处理此问题的内容。但是,以下是一个简单的示例。
在项目中添加一个新的Cocoa Touch类文件,将其命名为FirstViewController并将以下代码设置在其中:
import UIKit

class FirstViewController: UIViewController, DetailsDelegate {
    
    @IBOutlet weak var label: UILabel! // FIXME: link this to the UILabel in the Storyboard
    
    func updateLabel(withString string: String?) {
        label.text = string
    }
    
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        let controller = segue.destinationViewController as! SecondViewController
        controller.delegate = self
    }
    
}
在你的项目中添加一个新的Cocoa/Cocoa Touch类文件,将其命名为SecondViewController并将以下代码设置在其中:
import UIKit

protocol DetailsDelegate: class {
    func updateLabel(withString string: String?)
}

class SecondViewController: UIViewController {
    
    weak var delegate: DetailsDelegate?
    @IBOutlet weak var textField: UITextField! // FIXME: link this to the UITextField in the Storyboard
    
    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
        
        delegate?.updateLabel(withString: textField.text)
    }

}

在Storyboard中,将第一个视图控制器嵌入到UINavigationController中。使用UIButtonUIBarButtonItem将第一个视图控制器连接到第二个视图控制器。将第一个视图控制器的名称设置为FirstViewController,第二个视图控制器的名称设置为SecondViewController。在第一个视图控制器中创建一个UILabel。在第二个视图控制器中创建一个UITextField。将文本字段和标签链接到它们在FirstViewControllerSecondViewController中的相应声明。


3
没有segue的情况下,有没有实现类似这样的方法? - Ilir V. Gruda
嗨。我也遇到了同样的问题。但是在我的情况下,我没有使用Storyboard,而是使用XIB。那么,如果不使用segue,我该如何将第一个视图控制器中的委托引用发送到第二个视图控制器中呢? - Mano

16

Imanou Petit和Oscar Swanros已经正确回答了。但是我有一个相当“hacky”的替代方法,用于在没有连接它们的segue的情况下在2个视图控制器之间传输数据。

要获取您应用程序的根视图控制器,可以执行以下操作:

UIApplication.sharedApplication().windows[0].rootViewController

从那里开始,您可以获取您想要的任何视图控制器。例如,如果您想要根视图控制器的第二个子视图控制器,则可以执行以下操作:

let viewController = UIApplication.sharedApplication().windows[0].rootViewController?.childViewControllers[1] as? YourViewController
viewController?.yourProperty = newValue

请记住,这种方法相当“hacky”,可能违反最佳编码实践。


通过正确回答问题,为什么要提供一些“hacky”的东西,这可能违反了最佳编码实践呢? - Craig B

6
您需要在视图控制器之间创建一个Segue:
  1. 在您的Storyboard中,选择ViewController A
  2. 同时按住Control键,点击ViewController A,将蓝色线拖动到ViewController B。如果ViewController A嵌入在NavigationController中,则在松开时出现的菜单中选择“show”。否则,选择“present modally”。
  3. 在您的Storyboard上选择Segue,并在Utilities Panel上转到Attributes Inspector,为您的segue分配一个标识符(例如:“DetailSegue”)。
现在,当您想要在ViewController A上触发segue时,您只需要调用(可能是在按钮点击时):
@IBAction func buttonTapped() {
    self.performSegueWithIdentifier("DetailSegue", sender: self)
}

为了向ViewController B传递一个值,在ViewController A上重写prepareForSegue:sender方法:
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
    if segue.identifier == "DetailSegue" {
        var viewControllerB = segue.destinationViewController as ViewControllerB
        viewControllerB.text = self.textField.text
    }
}

很简单。请注意,为了使其起作用,您的“ViewController B”类应该如下所示:
class ViewControllerB: UIViewController {
    ver label = UILabel(...)
    var text: String? 

    override func viewDidLoad() {
        super.viewDidLoad()

        label.text = text!
    }
}

希望这能帮到你。

1
我们如何使用 Swift 在 FirstViewController 中创建 SecondViewController 的属性实例? - Nassif
谢谢!我卡在了如何在故事板中创建segue而不需要从viewController1附加按钮的问题上。 - Ann Taylor

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