显示的视图控制器被解除呈现时调用呈现的视图控制器的viewWillAppear方法存在问题

4
我目前有一个基本视图控制器,称为AVC,它通过当前上下文呈现另一个视图控制器,称为BVC,如下所示:

let bvc: BVC = sb.instantiateViewControllerWithIdentifier("BVC") as! BVC
bvc.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
self.presentViewController(bvc, animated: true, completion: nil)

我正在设置BVC中的值,并在dismiss时使用相同的值来执行AVC的viewWillAppear函数。然而,我注意到当presenting OverCurrentContext时,在dismiss时,viewWillAppear不被调用。

我应该如何解决这个问题?我需要一个半透明的presented view,因此需要使用OverCurrentContext。

谢谢!

2个回答

7

你好,

有两种方法:

方法1

你可以利用代理和协议来实现这个功能 :)

在BVC中声明一个协议并在AVC中确认它。当你在BVC完成后调用协议的方法,让AVC关闭BVC,这样就可以将数据从BVC传递到AVC。

例如:

在BVC中声明一个类似下面的协议

protocol letsCallParent{
    func amDoneHere(dataIwantToPass : String)
}

在BVC中声明一个属性来保存符合该协议的视图控制器的引用

var myParent : letsCallParent?

当你完成BVC并需要解散时,请在委托中调用该方法并传递要传递的数据 :) 现在,期望父级(AVC)解散BVC而不是在自身上调用dismissViewController将是良好的编码实践 :)

if let parent = myParent {
    parent.amDoneHere("Hi am Done here")
}

在 AVC 中确认使用协议

class AVC: UIViewController,letsCallParent{

在呈现 BVC 之前,实例化 BVC 并将自己作为 BVC 的 myParent 赋值给它 :)
let bvc: BVC = sb.instantiateViewControllerWithIdentifier("BVC") as! BVC
bvc.myParent = self

最后实现协议方法 :)

func amDoneHere(dataIwantToPass: String) {
   print("\(dataIwantToPass)")
   //if you want to dismiss BVC call 
   //if you have pushed bvc
   //self.navigationController?.popToViewController(self, animated: true)
   //if you have presented
   //self.dismissViewControllerAnimated(true, completion: nil)
}

方式2

利用取消segue :) 利用取消segue将消除编写代理和协议的需要,并且还提供了父视图控制器访问子视图控制器的机会 :) 一旦您可以访问子VC(即BVC),就可以从中读取数据 :)

示例:

声明一个取消segue :) 如果您希望BVC在关闭时调用AVC的方法,请在AVC中声明一个取消segue方法 :)

@IBAction func cancelChildVC(segue:UIStoryboardSegue) {
        let childVC : SecondViewController = segue.sourceViewController as! SecondViewController
        print(childVC.name)
        self.dismissViewControllerAnimated(true, completion: nil)
}

方法的签名是固定的 :) 它必须是 @IBAction,而且必须接受 segue 作为参数 :)

只有在声明这个方法后 :) 前往你的故事板并选择 BVC,然后从 BVC 中的按钮或任何其他视图上按住控制键并拖动到退出选项中即可将其解除 :)

请查看下面提供的 gif 以获得清晰的理解 :)

enter image description here

如果你做得正确,你会看到在 AVC 中声明的方法出现为弹出选项 :) 选择它 :) 就这样 :) 每当你点击按钮或视图从中你已经拖动控件到 Exit,你的 AVC 中的方法被调用 :) 在 AVC 的方法中,你可以访问 BVC 实例,因为现在你有了对 segue 实例的访问 :) 记住 prepareForSegue 方法用于直接 segue,这类似于 unwind segue :)
let childVC : SecondViewController = segue.sourceViewController as! SecondViewController
print(childVC.name)
self.dismissViewControllerAnimated(true, completion: nil) 

注意一旦您可以访问BVC,使用"segue.sourceViewController"来访问其数据 :)
希望我的回答有所帮助 :)

谢谢!var myParent 应该是 AVC 类型,而不是 letsCallParent,像这样 myParent:AVC。 - Shivam Bhalla
另外,在我的情况下,由于在解除BVC时没有调用AVC的任何方法,那么我在哪里调用amDoneHere()才能访问它? - Shivam Bhalla
@shivam-bhalla:根据你的问题,var myParent不应该是AVC类型吗?不需要。BVC不需要知道它的父视图控制器是AVC类型 :) 这会导致紧密耦合:) 这意味着如果其他视图控制器(比如CVC)呈现BVC,则将委托myParent设置为AVC将导致错误:) 你不想为每个视图控制器声明一个单独的委托,对吧,伙计 :) - Sandeep Bhandari
针对您的第二个问题:)当我解散BVC时,AVC的任何方法都不会被调用,那么我在哪里调用amDoneHere()? :) 您不需要在AVC上调用amDoneHere(),而是在myParent变量所指向的BVC中调用它:) 这将触发AVC中的代码:) 现在调用它的位置取决于您的程序逻辑:) 假设您在BVC中有一个名为dismiss的按钮,当您点击该按钮时,必须解散BVC:) 在该情况下,只需在该方法的IBAction中调用parent.amDoneHere(“Hi am Done here”)。 - Sandeep Bhandari
代理应该是“弱引用”,否则会创建一个保留循环。此外,尽量遵守命名约定:协议的名称应使用大驼峰式命名风格。同时,最好以单词“...Delegate”结尾。例如:ChildTaskDelegate - Starsky
显示剩余2条评论

4

问题解释

正如您所注意到的那样,当使用OverCurrentContext呈现视图时,viewWillAppear将不会在dismiss时被调用。

为什么?

viewWillAppear将在每次返回视图时调用(如果该视图已经消失)。当您使用OverCurrentContext呈现一个新视图时,主视图仍然存在,并且您在其上或其部分上呈现一个新视图!弹出效果!

因为这个逻辑,当您解除OverCurrentContext视图时,viewWillAppear不会被调用,您必须手动处理它,例如像@Sandeep以上所做的任何一种方式。


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