实施可重复使用的&可配置的ViewController

时间:2017-12-02 10:15:50

标签: ios swift xcode uiviewcontroller

在我的iOS应用中,我需要跨多个父ViewController使用通用模式GetData(我们称之为ViewControllers)。 GetData需要是可配置的(如隐藏/显示一些Views)。 GetData应该能够将数据返回到调用ViewController

根据我对网络上的SO和其他来源的阅读,以下是对我如何实施它的简化:

// ViewController.swift

import UIKit

class ViewController: UIViewController, GetDataDelegate {

    // This shows the data received from GetData
    @IBOutlet weak var textviewResult: UITextView!

    // Call GetData with only mandatory and without optional views
    @IBAction func onClickGetData(_ sender: Any) {
        let getData = GetData(caller: self)
        getData.display(delegate: self)
    }

    // Call GetData with both mandatory and optional data views
    @IBAction func onClickGetDataWithOptional(_ sender: Any) {
        let getData = GetData(caller: self, hasOptional: true)
        getData.display(delegate: self)
    }

    // Delegate function to received data sent by GetData
    func gotData(data1: String, data2: String!) {
        textviewResult.text = "Mandatory: \(data1)"
                + (data2 != nil ? "\nOptional: \(data2!)" : "")
    }
}
// GetData.swift

import UIKit

protocol GetDataDelegate {
    func gotData(data1: String, data2: String!)
}

class GetData: UIViewController {

    @IBOutlet weak var textfieldMandatory: UITextField!
    @IBOutlet weak var textfieldOptional: UITextField!
    // View with the optional views
    @IBOutlet weak var stackViewOptional: UIStackView!

    var delegate:GetDataDelegate?
    var caller:UIViewController?
    var hasOptional:Bool?

    init(caller: UIViewController, hasOptional: Bool? = false) {
        super.init(nibName: "GetData", bundle: nil)

        self.caller = caller
        self.hasOptional = hasOptional
    }

    func display(delegate:GetDataDelegate) {
        self.delegate = delegate

        let viewController = UIStoryboard(name: "GetData", bundle: nil).instantiateViewController(withIdentifier: "GetData")
        viewController.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
        viewController.modalTransitionStyle = UIModalTransitionStyle.crossDissolve

        caller?.present(viewController, animated: true, completion: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    @IBAction func onSubmit(_ sender: Any) {
        self.dismiss(animated: true, completion: nil)
        delegate?.gotData(data1: textfieldMandatory.text!, data2: hasOptional! ? textfieldOptional.text! : nil)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        // Configure GetData (hide/show views)
        // But hasOptional is nil!
        //stackViewOptional?.isHidden = !hasOptional!
    }
}

我面临以下问题:

  1. delegate未调用func GetData
  2. 我无法对GetData views进行更改(func viewWillAppear)。
  3. 上述两种情况似乎都是因为members delegatefunc onSubmit}和hasOptionalfunc {{ 1}})即使在初始化之后仍为viewWillAppear

    需要做出哪些更正,还是需要采用不同的方法?

    注意:以上是简化。在我的实际使用案例中,有多个视图控制器可以使用或不使用可选nil来调用GetData

2 个答案:

答案 0 :(得分:0)

我认为这可以更好地实现容器 - 您可以在一个屏幕上拥有多个视图控制器。 Dave DeLong写了关于这种方法的great articles

答案 1 :(得分:0)

我终于按照我的要求开始工作了:

// ViewController.swift

import UIKit

class ViewController: UIViewController, GetDataDelegate {

    // This shows the data received from GetData
    @IBOutlet weak var textviewResult: UITextView!

    // Call GetData with only mandatory and without optional views
    @IBAction func onClickGetData(_ sender: Any) {
        GetData.generate(caller: self)
    }

    // Call GetData with both mandatory and optional data views
    @IBAction func onClickGetDataWithOptional(_ sender: Any) {
        GetData.generate(caller: self, hasOptional: true)
    }

    // Delegate function to received data sent by GetData
    func gotData(data1: String, data2: String!) {
        textviewResult.text = "Mandatory: \(data1)"
                + (data2 != nil ? "\nOptional: \(data2!)" : "")
    }
}
// GetData.swift

import UIKit

protocol GetDataDelegate {
    func gotData(data1: String, data2: String!)
}

class GetData: UIViewController {

    @IBOutlet weak var textfieldMandatory: UITextField!
    @IBOutlet weak var textfieldOptional: UITextField!
    // View with the optional views
    @IBOutlet weak var stackViewOptional: UIStackView!  

    var delegate:GetDataDelegate?
    var hasOptional:Bool?

    static func generate(caller: UIViewController, hasOptional: Bool? = false) {
        let getData = UIStoryboard(name: "GetData", bundle: nil).instantiateViewController(withIdentifier: "GetData") as! GetData
        getData.delegate = caller as? GetDataDelegate
        getData.hasOptional = hasOptional
        caller.present(getData, animated: true, completion: nil)
    }

    @IBAction func onSubmit(_ sender: Any) {
        self.dismiss(animated: true, completion: nil)
        delegate?.gotData(data1: textfieldMandatory.text!, data2: hasOptional! ? textfieldOptional.text! : nil)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        // Configure GetData (hide/show views)
        stackViewOptional?.isHidden = !hasOptional!
    }
}

希望这是一种正确的方法......