swift如何控制ViewControllers之间的执行顺序?
How to control the order of execution between ViewControllers in swift?
我想实现的需求非常简单和常见,但我无法实现。我的示例代码尽可能简短,并应实现以下目标:
- 启动主视图。
- 在主视图上注册一个触摸事件。这将启动子视图。 (此调用定义了一个函数,该函数应在完成后开始。)
- 子视图打开。此子视图有一个 return 按钮。
- 按下此按钮后,控件将返回到主视图。
- 在主进程中,完成函数应该启动。
- 在主进程中,执行子视图调用(2)之后的语句。
但是我得到的执行顺序是这样的:
- 预期步骤 1(在主视图开始时)
- 预期的第 2 步(在 main 中点击后)
- 预期的第 3 步(在子视图开始时)
- 预期的第 6 步(在语句调用子视图之后)
- 预期步骤 5(在完成参数的函数中)
- 预期步骤 4(按下 return 按钮后)
步骤 3 和步骤 4 是通过 self.present... 和 self.dismiss... 实现的,因为我需要在我的项目中以编程方式实现这些步骤(比这个演示版本更复杂).这些方法确实有效。我的问题只是执行顺序。
如果这个问题的答案是 await 和 async: 不幸的是我不能使用它,因为我被限制在 Xcode 10 和 Swift 4。但我希望上面的问题一定是也可以用旧方法解决。由于我是这个开发平台的新手,所以很可能我对这个过程缺乏基本的了解。
现在是我的 Swift 代码。
主视图控制器代码:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("Intended step 1 (at main view start)")
}
@IBAction func gotoSubView(_ sender: UITapGestureRecognizer) {
print("Intended step 2 (after tap in main)")
let nextViewController =
self.storyboard?.instantiateViewController(withIdentifier:
"SubViewController") as! SubViewController
self.present(nextViewController, animated:true,
completion:IntendedAfterReturn)
print("Intended step 6 (after statement calling subview)")
}
func IntendedAfterReturn() {
print("Intended step 5 (in function of completion. parameter)")
}
}
子视图控制器代码:
import UIKit
class SubViewController: UIViewController {
@IBOutlet weak var btnReturn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
print("Intended step 3 (at sub view start)")
}
@IBAction func backToMain(_ sender: UIButton) {
print("Intended step 4 (after return Button is pressed)")
self.dismiss(animated: true, completion: nil)
}
}
函数 present(_:animated:completion:)
不允许您提供在用户关闭模式时运行的完成处理程序。当显示模态的动画结束时(当呈现的模态完全显示在屏幕上时)它调用完成处理程序。
您需要向第一个视图控制器的 viewDidAppear 方法添加一个处理程序(加上区分第一次调用和用户从子视图控制器返回的逻辑)
或者您需要向您的子视图控制器添加一个委托 属性 以告知调用者用户已关闭子视图控制器。 (我推荐这种方法。使用 viewDidAppear 很脆弱。)
Duncan 关于添加代表的建议 属性 是正确的答案,它让我找到了解决方案。我想在这里分享上面问题的代码,并通过委托机制进行了增强,以防它可以帮助遇到类似问题的人。为了理解 delegate/protocol 机制,我找到了 Sean Allen 的一个很棒的解释视频:https://www.youtube.com/watch?v=DBWu6TnhLeY
现在又是代码。主视图控制器代码:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("Intended step 1 (at main view start)")
}
@IBAction func gotoSubView(_ sender: UITapGestureRecognizer)
{
print("Intended step 2 (after tap in main)")
let nextViewController = self.storyboard?.instantiateViewController(withIdentifier: "SubViewController") as! SubViewController
nextViewController.selectionDelegate = self
self.present(nextViewController, animated:true, completion:nil)
}
}
extension ViewController: SubViewSelectionDelegate {
func IntendedAfterReturn(text: String) {
print("Intended step 5 (Text from subview is: \(text))")
}
func IntendedAfterReturnAlso(text: String) {
print("Intended step 6 (Text from subview is: \(text))")
}
}
子视图控制器代码:
import UIKit
protocol SubViewSelectionDelegate {
// Since we have only a primitive example here with 1 button, the function parameter would even not be necessary. But we include a parameter for demonstration.
func IntendedAfterReturn(text: String)
func IntendedAfterReturnAlso(text: String)
}
class SubViewController: UIViewController {
var selectionDelegate: SubViewSelectionDelegate!
@IBOutlet weak var btnReturn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
print("Intended step 3 (at sub view start)")
}
@IBAction func backToMain(_ sender: UIButton) {
print("Intended step 4 (after return Button is pressed)")
selectionDelegate.IntendedAfterReturn(text: "For first action after return button tap")
selectionDelegate.IntendedAfterReturnAlso(text: "For second action after return button tap")
self.dismiss(animated: true, completion: nil)
}
}
现在,当我运行这个程序时,输出如下:
- 预期的第 1 步(在主视图开始时)
- 预期的第 2 步(在 main 中点击后)
- 预期的第 3 步(在子视图开始时)
- 预期步骤 4(按下 return 按钮后)
- 预期的第 5 步(来自子视图的文本是:点击 return 按钮后的第一个动作)
- 预期的第 6 步(来自子视图的文本是:对于之后的第二个操作
return 点击按钮)
我想实现的需求非常简单和常见,但我无法实现。我的示例代码尽可能简短,并应实现以下目标:
- 启动主视图。
- 在主视图上注册一个触摸事件。这将启动子视图。 (此调用定义了一个函数,该函数应在完成后开始。)
- 子视图打开。此子视图有一个 return 按钮。
- 按下此按钮后,控件将返回到主视图。
- 在主进程中,完成函数应该启动。
- 在主进程中,执行子视图调用(2)之后的语句。
但是我得到的执行顺序是这样的:
- 预期步骤 1(在主视图开始时)
- 预期的第 2 步(在 main 中点击后)
- 预期的第 3 步(在子视图开始时)
- 预期的第 6 步(在语句调用子视图之后)
- 预期步骤 5(在完成参数的函数中)
- 预期步骤 4(按下 return 按钮后)
步骤 3 和步骤 4 是通过 self.present... 和 self.dismiss... 实现的,因为我需要在我的项目中以编程方式实现这些步骤(比这个演示版本更复杂).这些方法确实有效。我的问题只是执行顺序。
如果这个问题的答案是 await 和 async: 不幸的是我不能使用它,因为我被限制在 Xcode 10 和 Swift 4。但我希望上面的问题一定是也可以用旧方法解决。由于我是这个开发平台的新手,所以很可能我对这个过程缺乏基本的了解。
现在是我的 Swift 代码。 主视图控制器代码:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("Intended step 1 (at main view start)")
}
@IBAction func gotoSubView(_ sender: UITapGestureRecognizer) {
print("Intended step 2 (after tap in main)")
let nextViewController =
self.storyboard?.instantiateViewController(withIdentifier:
"SubViewController") as! SubViewController
self.present(nextViewController, animated:true,
completion:IntendedAfterReturn)
print("Intended step 6 (after statement calling subview)")
}
func IntendedAfterReturn() {
print("Intended step 5 (in function of completion. parameter)")
}
}
子视图控制器代码:
import UIKit
class SubViewController: UIViewController {
@IBOutlet weak var btnReturn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
print("Intended step 3 (at sub view start)")
}
@IBAction func backToMain(_ sender: UIButton) {
print("Intended step 4 (after return Button is pressed)")
self.dismiss(animated: true, completion: nil)
}
}
函数 present(_:animated:completion:)
不允许您提供在用户关闭模式时运行的完成处理程序。当显示模态的动画结束时(当呈现的模态完全显示在屏幕上时)它调用完成处理程序。
您需要向第一个视图控制器的 viewDidAppear 方法添加一个处理程序(加上区分第一次调用和用户从子视图控制器返回的逻辑)
或者您需要向您的子视图控制器添加一个委托 属性 以告知调用者用户已关闭子视图控制器。 (我推荐这种方法。使用 viewDidAppear 很脆弱。)
Duncan 关于添加代表的建议 属性 是正确的答案,它让我找到了解决方案。我想在这里分享上面问题的代码,并通过委托机制进行了增强,以防它可以帮助遇到类似问题的人。为了理解 delegate/protocol 机制,我找到了 Sean Allen 的一个很棒的解释视频:https://www.youtube.com/watch?v=DBWu6TnhLeY
现在又是代码。主视图控制器代码:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("Intended step 1 (at main view start)")
}
@IBAction func gotoSubView(_ sender: UITapGestureRecognizer)
{
print("Intended step 2 (after tap in main)")
let nextViewController = self.storyboard?.instantiateViewController(withIdentifier: "SubViewController") as! SubViewController
nextViewController.selectionDelegate = self
self.present(nextViewController, animated:true, completion:nil)
}
}
extension ViewController: SubViewSelectionDelegate {
func IntendedAfterReturn(text: String) {
print("Intended step 5 (Text from subview is: \(text))")
}
func IntendedAfterReturnAlso(text: String) {
print("Intended step 6 (Text from subview is: \(text))")
}
}
子视图控制器代码:
import UIKit
protocol SubViewSelectionDelegate {
// Since we have only a primitive example here with 1 button, the function parameter would even not be necessary. But we include a parameter for demonstration.
func IntendedAfterReturn(text: String)
func IntendedAfterReturnAlso(text: String)
}
class SubViewController: UIViewController {
var selectionDelegate: SubViewSelectionDelegate!
@IBOutlet weak var btnReturn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
print("Intended step 3 (at sub view start)")
}
@IBAction func backToMain(_ sender: UIButton) {
print("Intended step 4 (after return Button is pressed)")
selectionDelegate.IntendedAfterReturn(text: "For first action after return button tap")
selectionDelegate.IntendedAfterReturnAlso(text: "For second action after return button tap")
self.dismiss(animated: true, completion: nil)
}
}
现在,当我运行这个程序时,输出如下:
- 预期的第 1 步(在主视图开始时)
- 预期的第 2 步(在 main 中点击后)
- 预期的第 3 步(在子视图开始时)
- 预期步骤 4(按下 return 按钮后)
- 预期的第 5 步(来自子视图的文本是:点击 return 按钮后的第一个动作)
- 预期的第 6 步(来自子视图的文本是:对于之后的第二个操作 return 点击按钮)