【问题标题】:How to pass data from modal view controller back when dismissed关闭时如何从模态视图控制器传回数据
【发布时间】:2017-02-28 19:33:04
【问题描述】:

我已经按照here 的说明进行操作,但我仍然不确定这部分:

modalVC.delegate=self;
self.presentViewController(modalVC, animated: true, completion: nil) 

我尝试过以编程方式实例化视图控制器,但仍然无济于事。

这是我关闭模式视图控制器时的代码:

@IBAction func dismissViewController(_ sender: UIBarButtonItem) {
    self.dismiss(animated: true) { 
        //
    }
}

我正在使用情节提要与模态视图进行衔接。

这是我希望传回父视图控制器的数据:

var typeState = "top"
var categoryState = "casual"

这是两个字符串值。

我尝试从模态视图控制器传递数据,如下所示:

@IBAction func dismissViewController(_ sender: UIBarButtonItem) {
    self.dismiss(animated: true, completion: nil)
    delegate?.sendValue(value: "success")
    if let presenter = presentingViewController as? OOTDListViewController {
        presenter.receivedValue = "test"
    }
}

而在父视图控制器上我是这样做的:

func sendValue(value: NSString) {
    receivedValue = value as String
}

@IBAction func printReceivedValue(_ sender: UIButton) {
    print(receivedValue)
}

当我点击打印按钮时,我仍然无法收到任何值。

模态视图控制器:

protocol ModalViewControllerDelegate
{
    func sendData(typeState: String, categoryState: String)
}

var delegate:ModalViewControllerDelegate!

var typeState = "top"
var categoryState = "casual"
@IBAction func dismissViewController(_ sender: UIBarButtonItem) {
    self.dismiss(animated: true, completion: nil)
    delegate?.sendData(typeState: typeState as String, categoryState: categoryState as String)
}

父视图控制器:

class parentViewController: UICollectionViewController, ModalViewControllerDelegate {

var typeState: String?
var categoryState: String?

func sendData(typeState: String, categoryState: String) {
    self.typeState = typeState as String
    self.categoryState = categoryState as String
}

@IBAction func printReceivedValue(_ sender: UIButton) {
    print(typeState)
}

这是我没有使用委托方法的新代码:

模态视图控制器:

@IBAction func dismissViewController(_ sender: UIBarButtonItem) {
    self.dismiss(animated: true, completion: nil)
    if let presenter = presentingViewController as? OOTDListViewController {
        presenter.typeState = typeState
        presenter.categoryState = categoryState
    }
}

OOTDListViewController:

@IBAction func presentModalView(_ sender: UIBarButtonItem) {
    let modalView = storyboard?.instantiateViewController(withIdentifier: "filterViewController") as! ModalViewController
    let navModalView: UINavigationController = UINavigationController(rootViewController: modalView)
    self.present(navModalView, animated: true, completion: nil)
}

@IBAction func printValue(_ sender: UIButton) {
    print(typeState)
    print(categoryState)
}

【问题讨论】:

  • 你是用segue还是代码来展示viewcontroller?
  • 我正在展示带有故事板 segue 的模态视图
  • 打印仍然返回 nil 或空白答案
  • 您需要在关闭viewController之前设置值,否则presentingViewController将始终为nil。因此,将self.dismiss 调用移到dismissViewController 函数的末尾。
  • 还是不行。它与我启动导航控制器层次结构有什么关系吗?

标签: ios swift


【解决方案1】:

根据您要传递的数据,您可以在呈现视图控制器中创建一个属性,您可以在关闭模态视图控制器时设置该属性,这样您就可以省去委托。

例如,您有一个ContactsViewController,拥有一个var contacts: [Contact] = [] 属性。当你想创建一个新的联系人时,你会展示一个带有不同值的模态视图控制器,你需要创建一个新的Contact 对象。当您完成并想要关闭视图控制器时,您可以像在代码中那样调用该函数,但在 ContactsViewController 中设置属性。它看起来像这样:

@IBAction func dismissViewController(_ sender: UIBarButtonItem) {
    if let presenter = presentingViewController as? ContactsViewController {
        presenter.contacts.append(newContact)
    }
    dismiss(animated: true, completion: nil)
}

如果您不想想要使用委托,可以这样做:

在你的OOTDListViewController

var testValue: String = ""

@IBAction func printReceivedValue(_ sender: UIButton) {
    print(testValue)
}

在您的模态视图控制器中(我称之为PresentedViewController):

@IBAction func dismissViewController(_ sender: UIBarButtonItem) {
    // if your OOTDListViewController is part of a UINavigationController stack, this check will probably fail. 
    // you need to put a breakpoint here and check if the presentingViewController is actually a UINavigationController.
    // in that case, you will need to access the viewControllers variable and find your OOTDListViewController
    if let presenter = presentingViewController as? OOTDListViewController {
        presenter.testValue = "Test"
    }
    dismiss(animated: true, completion: nil)
}

如果您想要使用委托,可以这样做:

在您的 OOTDListViewController 中:

protocol ModalDelegate {
    func changeValue(value: String)
}
    
class OOTDListViewController: ModalDelegate {

    var testValue: String = ""
    @IBAction func presentViewController() {
        // here, you either create a new instance of the ViewController by initializing it, or you instantiate it using a storyboard. 
        // for simplicity, I'll use the first way
        // in any case, you cannot use a storyboard segue directly, bevause you need access to the reference of the presentedViewController object
        let presentedVC = PresentedViewController() 
        presentedVC.delegate = self
        present(presentedVC, animated: true, completion: nil)
    }

    func changeValue(value: String) {
         testValue = value
         print(testValue)
    }
}

在你的PresentedViewController:

class PresentedViewController {
    var delegate: ModalDelegate? 
    var testValue: String = ""

    @IBAction func dismissViewController(_ sender: UIBarButtonItem) {
       if let delegate = self.delegate {
            delegate.changeValue(testValue)
        }
        dismiss(animated: true, completion: nil)
    }

}

【讨论】:

  • 对不起,我真的不明白如何将值传递回父视图控制器。他们说使用在模态视图上创建协议的方法,然后创建一个函数,该函数将在父视图控制器中接收该值。除了我突出显示但无法获取任何数据的部分之外,我做了所有这些。
  • 我使用了非委托方法,并通过代码实例化了所有内容。但我需要导航栏,否则将没有顶部栏让我有一个完成按钮。我已经用我正在使用的当前代码更新了我的帖子。
  • 执行此操作的“首选”方法是什么?使用委托还是不使用委托!?
  • 我总是在这里使用委托。以这种方式在presentingViewController 中使用presentingViewController 会使两个VC 高度相互依赖。如果您决定从另一个视图控制器呈现视图控制器,您的关闭功能将被破坏,您将无法将数据传回。
  • 我同意@FOMDDeveloper,委托方法让一切都清楚,您需要将委托从呈现vc传递给呈现的vc,然后在呈现的vc中调用委托方法,没有隐藏的技巧,耦合更少。
【解决方案2】:

我使用的是标签栏,所以工作代码如下:

if let tabBar = self.presentingViewController as? UITabBarController {
    let homeNavigationViewController = tabBar.viewControllers![0] as? UINavigationController
    let homeViewController = homeNavigationViewController?.topViewController as! HomeController
    homeViewController._transferedLocationID = self.editingLocationID!
}

【讨论】:

    【解决方案3】:

    需要在dismissViewController方法中调用委托方法

    @IBAction func dismissViewController(_ sender: UIBarButtonItem) {
        delegate?.sendData(typeState: "top", categoryState: "casual")
        self.dismiss(animated: true) { 
            //
        }
     }
    

    在你的 Modal ViewController 类中创建委托

    weak var delegate: MyProtocol?
    

    在 MyProtocol 和您分配委托的 presentingViewController 中创建一个方法名称为 sendData 的协议,实现 MyProtocol 方法

    protocol MyProtocol: AnyObject {
        func sendData(typeState: String, categoryState: String)
    }
    
    class ViewController: UIViewController, MyProtocol {
        var typeState: String?
        var categoryState: String?
    
        override func viewDidApear() {
            super.viewDidApear()
            presentNewModalVC()
        }
        
        func presentNewModalVC() {
           let modalVC = NewModalViewControllerToBePresented()
           modalVC.delegate = self
           present(modalVC, animated: true)
        }
        
        func sendData(typeState: String, categoryState: String) {
           self.typeState = typeState
           self.categoryState = categoryState
        }
     }
    

    【讨论】:

    • 不,仍然无法正常工作。澄清一下,协议应该在模态视图控制器 swift 文件中创建,对吗?可能是因为我使用故事板 segue 来呈现模态视图控制器,这就是它不起作用的原因吗?
    • 协议应该与模态或呈现的类分开创建。按照给定的答案
    • 您在展示 viewController 之前缺少来自 ViewController 的 vc.delegate = self
    • 编辑了答案,谢谢
    【解决方案4】:

    如果使用导航控制器,您必须首先获取 UINavigation 控制器,然后从导航控制器堆栈中获取正确的 ViewController。

    这是我的代码在这种情况下的样子。

    @IBAction func dismissViewController(_ sender: UIBarButtonItem) {
        if let navController = presentingViewController as? UINavigationController {
           let presenter = navController.topViewController as! OOTDListViewController
            presenter.testValue = "Test"
        }
        dismiss(animated: true, completion: nil)
    }
    

    【讨论】:

    • 这对我来说适用于顶级导航控制器
    猜你喜欢
    • 1970-01-01
    • 2017-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-01
    相关资源
    最近更新 更多