问题描述
我有两个视图控制器(ViewController 和 ActionViewController)和一个管理器(Brain),第二个视图控制器在用户访问时显示通过在情节提要中创建的显示转场点击按钮并返回到第一个,我在第二个视图控制器中使用了 self.dismiss。
用户在 ActionViewController 上输入一个需要在 ViewController 中检索的数字。所以我创建了 Brain 来使用委托模式。
问题是 ViewController 中的委托函数从未运行,我阅读了其他 SO 答案,但没有任何效果。我使用 print 语句来知道代码不再运行的地方,唯一没有运行的块是 ViewController
中的 didUpdatePrice这是代码
视图控制器
class ViewController: UIViewController,BrainDelegate {
var brain = Brain()
@IBOutlet var scoreLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
brain.delegate = self
scoreLabel.layer.cornerRadius = 25
scoreLabel.layer.masksToBounds = true
}
func didUpdatescore(newscore: String) {
print("the new label is \(newscore)")
scoreLabel.text = newscore
}
}
ActionViewController
class ActionViewController: UIViewController {
var brain = Brain()
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func addButtonTapped(_ sender: Any) {
brain.newAction(actualscore: 0,newActionValue: 5,isPositive: true)
self.dismiss(animated: true)
}
}
大脑
protocol BrainDelegate {
func didUpdatescore(newscore: String)
}
struct Brain {
var delegate: BrainDelegate?
func newAction(actualscore: Int,newActionValue: Int,isPositive: Bool) {
let newscore: Int
if isPositive {
newscore = actualscore + newActionValue
} else {
newscore = actualscore - newActionValue
}
print("the new score is \(newscore)")
delegate?.didUpdatescore(newscore: String(newscore))
}
}
解决方法
首先,在 Brain
上,您应该使用 class,而不是 struct。那是因为当您使用 struct 时,将变量传递给另一个将进行复制,它不会使用相同的引用。而且 class 只会复制引用。
这意味着您的 Brain
结构将失去在 .delegate = self
上分配的委托
第二,您需要在第二个 viewController 和第一个上使用相同的实例。像这样:
在第一个视图控制器上
var brain = Brain()
// this one is the one that you will put your "brain.delegate = self"
在第二个 viewController 上,您需要将此变量从第一个 viewController 注入第二个。那就是在两者上保持相同的实例。这将使委托可调用。
要使用 Storyboard 执行此操作,您将在第一个 ViewController 上执行此操作:
// this function should be called when the next viewController should open.
override func prepare(for segue: UIStoryboardSegue,sender: Any?) {
switch segue.destination) {
case let vc as MyViewController:
vc.brain = self.brain
default:
break
}
}
super.prepare(for: segue,sender: sender)
}
在第二个 viewController 中,使用:
var brain: Brain?
,
你根本不需要额外的 Brain
类/结构,你可以通过简单的协议和协议的默认扩展来实现。
第 1 步:选择您的节目转场并在故事板中提供一个标识符,如下所示
第 2 步:在您的 ViewController 中添加 prepare(for segue
方法
override func prepare(for segue: UIStoryboardSegue,sender: Any?) {
if segue.identifier == "testIdentifier" {
guard let destinationViewController = segue.destination as? ActionViewController else { return }
destinationViewController.delegate = self
}
}
第 3 步:在您的 ActionViewController
中声明一个名为 delegate
class ActionViewController: UIViewController {
weak var delegate: BrainDelegate? = nil
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func addButtonTapped(_ sender: Any) {
delegate?.newAction(actualScore: 0,newActionValue: 5,isPositive: true)
self.dismiss(animated: true)
}
}
第 4 步:将 class
子句添加到您的 BrainDelegate
(类绑定协议),以便您可以持有对委托的弱引用
protocol BrainDelegate: class {
func didUpdateScore(newScore: String)
func newAction(actualScore: Int,newActionValue: Int,isPositive: Bool)
}
第 5 步:
为 BrainDelegate
添加默认扩展并提供 newAction(actualScore:
的默认实现
extension BrainDelegate {
func newAction(actualScore: Int,isPositive: Bool) {
let newScore: Int
if isPositive {
newScore = actualScore + newActionValue
} else {
newScore = actualScore - newActionValue
}
print("the new score is \(newScore)")
self.didUpdateScore(newScore: String(newScore))
}
}
第 6 步:在您的 ActionViewController
中,只需将委托方法触发为
@IBAction func addButtonTapped(_ sender: Any) {
delegate?.newAction(actualScore: 0,isPositive: true)
self.dismiss(animated: true)
}
这应该可以完成工作