【问题标题】:Finding it difficult to pass data to separate viewController发现很难将数据传递给单独的 viewController
【发布时间】:2017-11-13 19:06:26
【问题描述】:

我已经在网上搜索了几个小时,现在认为这将是一件容易的事,但事情并没有按计划进行。这个问题已编辑,一些伟大的家伙给出了很好的答案,但我仍在努力。

这是场景,我有一个始终可见的 viewControllerA。这个视图顶部有一个小按钮,当我点击它时,会出现 viewControllerB 作为静态 tableViewController。老实说,它像其他应用程序一样是从左到右的幻灯片视图。

tableView 中有一个部分和几行,当我点击显示 viewControllerC 的第 4 行时,那里有一个 UISwitch 按钮。当我关闭 viewControllerC 时,viewControllerA 再次出现。 viewControllerB 是我的菜单控制器,因此它不是我更关心的问题。现在我想将数据从 viewControllerC 传递到 viewControllerA。这是我损坏的代码:

对于viewControllerC

class viewControllerC: UIViewController {
 ..//
 @IBAction func switchTapped(_ sender: UISwitch) {
     let vc = viewControllerA()
     if sender.isOn == true {
         vc.state = true
     } else if sender.isOn == false {
         vc.state = false
     }   
  }
 ..//
}

对于 viewControllerA

class viewControllerA: UIViewController, GMSMapViewDelegate {
  var state:Bool?
  ...//
  if self.state == true {
      self.mapView.isTrafficEnabled = true
    } else {
      self.mapView.isTrafficEnabled = false
   } 
}

但它不起作用,我知道我没有朝着正确的方向前进。从示例中可以看出,我想在 UISwitchon 时发送 ture 并在其 时发送 false >offviewControllerCviewControllerA。有些人建议使用委托方法,但我仍在苦苦挣扎。我正在关注这个 link ,我认为“通过应用程序的共享状态向后传递数据”部分符合我的标准。虽然我需要帮助。提前致谢。

【问题讨论】:

  • 与问题无关,但您可以将代码分别减少为一行:vc.state = sender.isOnself.mapView.isTrafficEnabled = self.state。问题的原因很可能是viewControllerA()的结果不是Interface Builder中设计的实例。

标签: ios swift


【解决方案1】:

您可以使用委托模式传递数据,这是一个想法:

import UIKit

// Make a delegate protocol
protocol ViewControllerBDelegate: class {
    func didTapSwitch(isOn: Bool)
}

class ViewControllerB: UIViewController {

    // Make a weak delegate reference in VC B
    weak var delegate: ViewControllerBDelegate?

    var state: Bool?

    // On action trigger delegate method:
    @IBAction func switchTapped(_ sender: UISwitch) {
        delegate?.didTapSwitch(isOn: sender.isOn)
    }

}

class ViewControllerA: UIViewController {

    var stateFromSwitch: Bool?
    // In this VC you are instantiating viewController B
    // ... code ...
    // set delegate: viewControllerB.delegate = self
}

// implement ViewControllerBDelegate
extension ViewControllerA: ViewControllerBDelegate {
    func didTapSwitch(isOn: Bool) {
        stateFromSwitch = isOn
    }
}

【讨论】:

  • @Oleh 你能看一下编辑过的问题吗,我很挣扎 :(
  • @ArafinRussell 当您点击第 4 行时,您实例化了一个具有委托引用的 ViewController(查看我的代码),您在其中点击 Switch,IBAction 使用 Bool 触发委托方法(true/false ) 它被传递回 ViewController,您在其中设置了 viewcontrollerc.delegate = self 并实现了委托方法,就是这样。您是否尝试实现该模式?我在你的问题中没有看到更新的代码兄弟,尝试先复制粘贴并弄清楚它是如何工作的,然后写下你失败的地方:)
【解决方案2】:

首先当你启动 viewControllerA 时:

让 vc = viewControllerA()

您正在创建未引用您的第一个视图控件的新视图控件实例。

您可以通过不同的方式将数据传递给视图控制器。 您可以使用 delage 模式,也可以使用 unwind。

在委托方法中,首先定义一个类类型协议,其中包含一个函数定义,用于更改 viewControllerA 中的某些内容。

protocol ViewControllerBDelegate: class {
    func changeSwitch(toValue: Boolean)
}

然后在 ViewControllerB 中定义一个对委托的弱引用

weak var delegate: ViewControllerBDelegate?

然后你在 ViewControlA 上采用这个协议:

extension ViewControllerA: ViewControllerBDelegate {
    func changeSwitch(toValue: Boolean) {
         state = toValue
     }
}

当你想展示或推送到 ViewControllerB 时,你应该将此变量设置为 self

let vc = ViewControllerB()
vc.delegate = self
present(vc, animated: true, completion: nil)
// or navigationController. pushViewController(vc, animated: true)

如果您使用 segue 从一个视图控制器导航到另一个视图控制器,您应该在 prepare(for segue, sender) 中设置委托变量。在 ViewControllerA 中重写此函数

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "mySegue" , 
       let vc = segue.destination as? ViewControllerB {
        vc.delegate = self
    }
}

那么当switch值改变时,你可以使用delegate来改变ViewControllerA中的值

delegate?.changeSwitch(toValue: sender.isOn)

on wind 让您将子视图控制器弹出或关闭到某个父级,然后执行某些操作。你可以阅读完整教程here

编辑

对于链委托,您可以将委托传递给 ViewController B,然后将相同的委托传递给 ViewController C。

在视图控制器 C 中定义相同类型的委托

weak var delegate: ViewControllerBDelegate?

然后在视图控制器 B 中,当您导航到视图控制器 c 时,您会传递相同的委托

let vc = ViewControllerC()
vc.delegate = self.delegate
present(vc, animated: true, completion: nil)

编辑 2

SWRevealViewController 是不同的场景。 revealController 有一个名为 frontViewController 的属性。如果您不推动任何其他控制器显示,它可以是您的 ViewControllerA。使用 frontViewController 处理它很棘手,您应该确定 frontController 是否为 ViewControllerA。

所以我建议您使用另一种方法与 ViewControllerA 进行通信。你可以使用通知中心。

extension Notification.Name {
    static let updateMap = Notification.Name("updateMap")
}

在 ViewControllerA 中

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(updateMap(_:)), name: .updateMap, object: nil )
}

@objc func updateMap(notification: NSNotification) {
  if let state = notification.userInfo?["state"] as? Bool {
      // do something with state
  }
}

在 ViewControllerC 中,当开关值发生更改时,您会发布通知:

let userInfoDic:[String: Bool] = ["state": sender.isOn]
  // post a notification
  NotificationCenter.default.post(name: .updateMap, object: nil, userInfo: userInfoDic)

如果再次推送reveal中的frontViewController。揭示将启动 frontViewController 的新 ViewControllerA。在这种情况下,您有 在 UserDefault 和 ViewControllerA 中设置设置阅读此 设置。

使用用户默认值:

在 ViewControllerC 中

UserDefaults.standard.setValue(sender.isOn, forKey: "mapState")

在 ViewControllerA 中

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    let state = UserDefaults.standard.value(forKey: "mapState") ?? false
    self.mapView.isTrafficEnabled = state
}

【讨论】:

  • 能否请您看一下已编辑的问题,我正在苦苦挣扎:(
  • 这真的取决于你如何实现侧边菜单。您是否使用库来创建侧边菜单?如果是,请告诉我哪个图书馆,以便我可以帮助您。通常,您可以链接委托以通过视图控制器传递数据。我要为链代表编辑我的答案
  • @ArafinRussell 通知
  • SWRevealViewController 伴侣
  • @ArafinRussell 更新了 RevealViewController 的答案。如果您的revealController 不推送或设置另一个ViewController,那么您可以使用NotificationCenter。但是如果它推送或设置一个新的 FrontViewController 那么你必须在 UserDefaults 和 ViewControllerA 中保存状态(你传递的布尔值)从 UserDefaults 读取状态并配置你的地图
猜你喜欢
  • 2018-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-01
  • 2019-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多