【问题标题】:How to call a function in the first controller after dismissing the second controller关闭第二个控制器后如何在第一个控制器中调用函数
【发布时间】:2018-04-02 23:10:03
【问题描述】:

我有两个 UIViewController,当我单击一个按钮时,它会从第一个视图控制器转到第二个。在此之前,我为 UIView 设置了动画以移动到另一个地方。关闭第二个视图控制器后,我想将第一个视图控制器中的 UIView 移回原来的位置。但是,当我从第二个视图控制器调用一个函数以在关闭第二个视图控制器后为第一个视图控制器中的 UIview 设置动画时,它无法获取 UIView 的属性,并且无法对其执行任何操作。我认为是因为第一个 UIViewController 尚未加载。那是问题吗?我应该如何解决这个问题?

【问题讨论】:

  • 请分享您的代码

标签: ios swift uiviewcontroller


【解决方案1】:

有两种解决方案可以使用快速闭包

class FirstViewController: UIViewController {

      @IBAction func start(_ sender: Any) {
           guard let secondController = self.storyboard?.instantiateViewController(withIdentifier: "SecondController") as? SecondController else { return }
        secondController.callbackClosure = { [weak self] in
            print("Do your stuff")
        }
        self.navigationController?.pushViewController(secondController, animated: true)
       }
}
//----------------------------

class SecondController: UIViewController {

      var callbackClosure: ((Void) -> Void)?

      override func viewWillDisappear(_ animated: Bool) {
         callbackClosure?()
          }
 }

或者你可以使用协议

class FirstViewController: UIViewController {

@IBAction func start(_ sender: Any) {
       guard let secondController = self.storyboard?.instantiateViewController(withIdentifier: "SecondController") as? SecondController else { return }
        secondController.delegate = self
    self.navigationController?.pushViewController(secondController, animated: true)
   }    

}

extension ViewController : ViewControllerSecDelegate {

    func didBackButtonPressed(){
         print("Do your stuff")
    }
}
//--------------------------


protocol SecondControllerDelegate : NSObjectProtocol {
    func didBackButtonPressed()
}

class SecondController: UIViewController {

    weak var delegate: SecondControllerDelegate?

         override func viewWillDisappear(_ animated: Bool) {
              delegate?.didBackButtonPressed()
         }
 }

【讨论】:

    【解决方案2】:

    您可以尝试使用闭包。像这样的:

    class FirstViewController: UIViewController {
    
        @IBOutlet weak var nextControllerButton: UIButton!
        private let animatableView: UIView = UIView()
    
        private func methodsForSomeAnimation() {
            /* 
             perform some animation with 'animatableView'
            */
        }
    
        @IBAction func nextControllerButtonAction() {
            // you can choose any other way to initialize controller :)
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            guard let secondController = storyboard.instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController else { return }
            secondController.callbackClosure = { [weak self] in
                self?.methodsForSomeAnimation()
            }
            present(secondController, animated: true, completion: nil)
        }
    }
    
    class SecondViewController: UIViewController {
    
        @IBOutlet weak var dismissButton: UIButton!
        var callbackClosure: ((Void) -> Void)?
    
        @IBAction func dismissButtonAction() {
            callbackClosure?()
            dismiss(animated: true, completion: nil)
            /* 
             or you call 'callbackClosure' in dismiss completion
             dismiss(animated: true) { [weak self] in
                 self?.callbackClosure?()
             }
            */
        }
    
    }
    

    【讨论】:

      【解决方案3】:

      当您展示您的第二个视图控制器时,您可以传递第一个视图控制器的实例。

      第二个 VC 可以像这样保存第一个 VC 的实例:

      weak var firstViewController: NameOfController?
      

      那么当您展示第二个 VC 时,请确保您设置的值不会像这样为 nil:

      firstViewController = self
      

      完成此操作后,您将能够访问该 viewControllers 函数。

      【讨论】:

      • 这是一种方法,但请记住输入“弱”。它应该看起来像:weak var firstViewController: NameOfController?。没有它,您将拥有保留周期,并且永远不会清理内存
      • @MichałKwiecień 非常正确,我已经更新了我的答案以反映这一点。
      【解决方案4】:

      iOS 11.x Swift 4.0

      在调用 VC 时你把这段代码...

      private struct Constants {
          static let ScannerViewController = "Scan VC"
      }
      
      override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
       if segue.identifier == Constants.ScannerViewController {
              let svc = destination as? ScannerViewController
              svc?.firstViewController = self
          }
      }
      

      您在我的案例中将 segue 命名为“Scan VC”,这就是它在 Xcode 面板中的样子。

      现在在 scan VC 中,我们在类声明下得到了这个

      weak var firstViewController: HiddingViewController?
      

      现在稍后在您的代码中,当您准备好返回时,我只需像这样在我的 firstViewController 中设置我关心的变量...

      self.firstViewController?.globalUUID = code
      

      我在 HiddingViewController 中这样设置...

      var globalUUID: String? {
          didSet {
              startScanning()
          }
      }
      

      所以基本上当我关闭扫描 VC 时,我设置了变量 globalUUID,它在此处启动扫描方法。

      【讨论】:

        【解决方案5】:

        当您说它无法获取 UIView 的属性时,是因为您将其设为私有?为什么在第一个控制器消失之前你不替换你的 UIView 去你的 secondViewController。我认为这是您必须清理视图控制器状态才能进一步使用第二个视图控制器的情况。

        通过 Apple 文档检查 IOS 生命周期方法:viewWillDisappearviewDidDisappear,然后使用其中一种方法制作动画。

        【讨论】:

          【解决方案6】:

          实际上非常简单的解决方案...只需将您的动画放在 viewDidAppear 方法中即可。每次加载视图时都会调用此方法。

          class firstViewController: UIViewController {
          
              override func viewDidAppear(_ animated: Bool) {
                  super.viewDidAppear(animated)
          
                  // insert animation here to run when FirstViewController appears...
              }
          }
          

          【讨论】:

            猜你喜欢
            • 2020-02-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-12-02
            相关资源
            最近更新 更多