导航堆栈之前的视图之间的协议委托
Protocol delegate between view before navigation stack
View1
转至 Navigation Controller - View2
转至 View3
我正在尝试创建从 View3 到 View1 的协议委托
在视图 1 中
class NormalUser: UIViewController, NormalUserDelegate {
@objc func showAddressView() {
addressView.isHidden = false
}
override func viewDidLoad() {
super.viewDidLoad()
if let conn = self.storyboard?.instantiateViewController(withIdentifier: "View") as? View
{
conn.delegate = self
}
}
}
在视图 3 中
weak var delegate: NormalUserDelegate?
func test() {
self.delegate?.showAddressView()
}
协议
protocol NormalUserDelegate: class {
func showAddressView()
}
我无法让它工作。有什么想法吗?
如果我对您的方案的理解正确,您需要两个委托,每个委托将数据传回前一个 UIViewController。据我所知,您不能绕过辅助 UIViewController。
您缺少的是路由器 class,这是我将如何实现它的一个简单示例。
protocol RoutingView1{
func openView2()
}
protocol RoutingView2{
func openView3()
}
protocol RoutingView3{
func foo()
}
class View1{
func foo(){
//this will get called when View3 calls its RootingView3.foo()
}
}
class Router: RoutingView1, RoutingView2{
var rootView: View1
func start() -> UIViewController{
view.routingDelegate = self
rootView = view1
}
func openView2(){
let vc = View2()
vc.routingDelegate = self
rootView.push()
}
func openView3(){
let vc = View3()
vc.routingDelegate = self
rootView.push()
}
func foo(){
rootView.foo()
}
在我看来,您有 2 个不错的选择来使用委托模式。 1 个糟糕的选项可以工作,但它很笨拙和懒惰,然后你就有了广播接收器模式。
2 个不错的选择
1 - 向前传递委托
class VC1: UIViewController, SomeDelegate {
func delegateFunction() {}
func showNextVC() {
let next = VC2()
next.forwardingDelegate = self
present(next, animated: true)
}
}
class VC2: UIViewController {
var forwardingDelegate: SomeDelegate? = nil
func showNextVC() {
let next = VC3()
next.delegate = forwardingDelegate
present(next, animated: true)
}
}
2 - 将第三个控制器传递给第二个控制器
class VC1: UIViewController, SomeDelegate {
func delegateFunction() {}
func showNextVC() {
let final = VC3()
final.delegate = self
let next = VC2(withControllerToPresent: final)
present(next, animated: true)
}
}
class VC2: UIViewController {
let controller: UIViewController
init(withControllerToPresent controller: UIViewController) {
self.controller = controller
super.init(withNibName: nil, bundle: nil
}
func showNextVC() {
present(controller, animated: true)
}
}
class VC3: UIViewController {
var delegate: SomeDelegate? = nil
}
1 个糟糕的选择
使用 singleton/global 变量....(请不要)
个人意见
我已经完成了前两个选项...它们有效。但是广播接收器模式可能更好,因为它会更干净。 VC2 不需要将任何内容转发给 3。只需确保将通知命名空间足够具体,以免以后被其他任何内容捕获。
解除 Segues
如果您使用的是界面生成器,则可能 easiest/cleanest 使用展开转场。
在 VC1 中创建界面生成器操作:
class VC1: UIViewController {
@IBAction func backToVC1(_ segue: UIStoryboardSegue) {
self.showAddress()
}
func showAddress() {
addressView.isHidden = false
}
}
在您的 VC3 故事板中,按住 Control 键并单击视图控制器图标,将鼠标拖到退出图标上并松开。单击 select 您在 VC1 中创建的 unwind segue。
在文档大纲中创建 segue select 后。
并在属性检查器中命名。
最后,在您的 VC3 代码中调用 segue。
class VC3: UIViewController {
func test() {
self.performSegue(withIdentifier: "unwindToVC1", sender: self)
}
}
我认为您可以使用 SwiftEventBus
来应对这种情况。 Link
示例:
@IBAction func clicked(sender: AnyObject) {
count++
SwiftEventBus.post("doStuffOnBackground")
}
@IBOutlet weak var textField: UITextField!
var count = 0
override func viewDidLoad() {
super.viewDidLoad()
SwiftEventBus.onBackgroundThread(self, name: "doStuffOnBackground") { notification in
println("doing stuff in background thread")
SwiftEventBus.postToMainThread("updateText")
}
SwiftEventBus.onMainThread(self, name: "updateText") { notification in
self.textField.text = "\(self.count)"
}
}
//Perhaps on viewDidDisappear depending on your needs
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
SwiftEventBus.unregister(self)
}
**Just set delegate of view 2 as a delegate of view 3 as below:**
class View1: UIViewController, NormalUserDelegate {
@objc func showAddressView() {
addressView.isHidden = false
}
// Going to view 2 by any means i.e segue , navigation set
func goToView2Controller(){
if let view2 = self.storyboard?.instantiateViewController(withIdentifier: "View2") as? View2
{
view2.delegate = self
}
self.navigationController?.pushViewController(view2, animated: true)
}
}
class View2: UIViewController {
weak var delegate: NormalUserDelegate?
// Going to view 3 by any means i.e segue or other means
func goToView3Controller(){
if let view3 = self.storyboard?.instantiateViewController(withIdentifier: "View3") as? View3
{
view3.delegate = self.delegate
}
self.navigationController?.pushViewController(view3, animated: true)
}
}
class View3: UIViewController {
weak var delegate: NormalUserDelegate?
func test() {
self.delegate?.showAddressView()
}
}
View1
转至 Navigation Controller - View2
转至 View3
我正在尝试创建从 View3 到 View1 的协议委托
在视图 1 中
class NormalUser: UIViewController, NormalUserDelegate {
@objc func showAddressView() {
addressView.isHidden = false
}
override func viewDidLoad() {
super.viewDidLoad()
if let conn = self.storyboard?.instantiateViewController(withIdentifier: "View") as? View
{
conn.delegate = self
}
}
}
在视图 3 中
weak var delegate: NormalUserDelegate?
func test() {
self.delegate?.showAddressView()
}
协议
protocol NormalUserDelegate: class {
func showAddressView()
}
我无法让它工作。有什么想法吗?
如果我对您的方案的理解正确,您需要两个委托,每个委托将数据传回前一个 UIViewController。据我所知,您不能绕过辅助 UIViewController。
您缺少的是路由器 class,这是我将如何实现它的一个简单示例。
protocol RoutingView1{
func openView2()
}
protocol RoutingView2{
func openView3()
}
protocol RoutingView3{
func foo()
}
class View1{
func foo(){
//this will get called when View3 calls its RootingView3.foo()
}
}
class Router: RoutingView1, RoutingView2{
var rootView: View1
func start() -> UIViewController{
view.routingDelegate = self
rootView = view1
}
func openView2(){
let vc = View2()
vc.routingDelegate = self
rootView.push()
}
func openView3(){
let vc = View3()
vc.routingDelegate = self
rootView.push()
}
func foo(){
rootView.foo()
}
在我看来,您有 2 个不错的选择来使用委托模式。 1 个糟糕的选项可以工作,但它很笨拙和懒惰,然后你就有了广播接收器模式。
2 个不错的选择
1 - 向前传递委托
class VC1: UIViewController, SomeDelegate {
func delegateFunction() {}
func showNextVC() {
let next = VC2()
next.forwardingDelegate = self
present(next, animated: true)
}
}
class VC2: UIViewController {
var forwardingDelegate: SomeDelegate? = nil
func showNextVC() {
let next = VC3()
next.delegate = forwardingDelegate
present(next, animated: true)
}
}
2 - 将第三个控制器传递给第二个控制器
class VC1: UIViewController, SomeDelegate {
func delegateFunction() {}
func showNextVC() {
let final = VC3()
final.delegate = self
let next = VC2(withControllerToPresent: final)
present(next, animated: true)
}
}
class VC2: UIViewController {
let controller: UIViewController
init(withControllerToPresent controller: UIViewController) {
self.controller = controller
super.init(withNibName: nil, bundle: nil
}
func showNextVC() {
present(controller, animated: true)
}
}
class VC3: UIViewController {
var delegate: SomeDelegate? = nil
}
1 个糟糕的选择
使用 singleton/global 变量....(请不要)
个人意见
我已经完成了前两个选项...它们有效。但是广播接收器模式可能更好,因为它会更干净。 VC2 不需要将任何内容转发给 3。只需确保将通知命名空间足够具体,以免以后被其他任何内容捕获。
解除 Segues
如果您使用的是界面生成器,则可能 easiest/cleanest 使用展开转场。
在 VC1 中创建界面生成器操作:
class VC1: UIViewController { @IBAction func backToVC1(_ segue: UIStoryboardSegue) { self.showAddress() } func showAddress() { addressView.isHidden = false } }
在您的 VC3 故事板中,按住 Control 键并单击视图控制器图标,将鼠标拖到退出图标上并松开。单击 select 您在 VC1 中创建的 unwind segue。
在文档大纲中创建 segue select 后。
并在属性检查器中命名。
最后,在您的 VC3 代码中调用 segue。
class VC3: UIViewController { func test() { self.performSegue(withIdentifier: "unwindToVC1", sender: self) } }
我认为您可以使用 SwiftEventBus
来应对这种情况。 Link
示例:
@IBAction func clicked(sender: AnyObject) {
count++
SwiftEventBus.post("doStuffOnBackground")
}
@IBOutlet weak var textField: UITextField!
var count = 0
override func viewDidLoad() {
super.viewDidLoad()
SwiftEventBus.onBackgroundThread(self, name: "doStuffOnBackground") { notification in
println("doing stuff in background thread")
SwiftEventBus.postToMainThread("updateText")
}
SwiftEventBus.onMainThread(self, name: "updateText") { notification in
self.textField.text = "\(self.count)"
}
}
//Perhaps on viewDidDisappear depending on your needs
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
SwiftEventBus.unregister(self)
}
**Just set delegate of view 2 as a delegate of view 3 as below:**
class View1: UIViewController, NormalUserDelegate {
@objc func showAddressView() {
addressView.isHidden = false
}
// Going to view 2 by any means i.e segue , navigation set
func goToView2Controller(){
if let view2 = self.storyboard?.instantiateViewController(withIdentifier: "View2") as? View2
{
view2.delegate = self
}
self.navigationController?.pushViewController(view2, animated: true)
}
}
class View2: UIViewController {
weak var delegate: NormalUserDelegate?
// Going to view 3 by any means i.e segue or other means
func goToView3Controller(){
if let view3 = self.storyboard?.instantiateViewController(withIdentifier: "View3") as? View3
{
view3.delegate = self.delegate
}
self.navigationController?.pushViewController(view3, animated: true)
}
}
class View3: UIViewController {
weak var delegate: NormalUserDelegate?
func test() {
self.delegate?.showAddressView()
}
}