实现可重用和可配置的 ViewController
Posted
技术标签:
【中文标题】实现可重用和可配置的 ViewController【英文标题】:Implement Reusable & Configurable ViewController 【发布时间】:2017-12-02 10:15:49 【问题描述】:在我的 ios 应用程序中,我需要一个跨多个父级 ViewControllers
的通用模式 ViewController
(我们称之为 GetData
)。 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!
我面临以下问题:
delegate
func
未在 GetData
中调用。
我无法更改GetData
views
(在func
viewWillAppear
)。
以上两者似乎都是因为members
delegate
(在func
onSubmit
)和hasOptional
(在func
viewWillAppear
)即使在初始化之后也是nil
。
需要进行哪些更正或者我需要采用不同的方法?
注意:以上为简化。在我的实际用例中,有多个视图控制器将调用GetData
,有或没有可选的Views
。
【问题讨论】:
创建一个类GetData
的实例(init(caller:
)然后再创建同一个类的另一个实例(instantiateViewController
)的目的是什么?
【参考方案1】:
我认为用容器来实现会更好——你可以在一个屏幕上拥有多个视图控制器。 Dave DeLong 就这种方法写了great articles。
【讨论】:
【参考方案2】:我终于按照我的要求让它工作了:
// 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!
希望这是一个正确的方法...
【讨论】:
以上是关于实现可重用和可配置的 ViewController的主要内容,如果未能解决你的问题,请参考以下文章
在 ViewController 中使用带有外部 DataSource 和 UITableView 的自定义 UITableViewCell