【问题标题】:Delegate function not called未调用委托函数
【发布时间】:2021-05-31 05:41:00
【问题描述】:

我有两个视图控制器(ViewControllerActionViewController)和一个管理器(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))
        
    }
}

【问题讨论】:

    标签: ios swift delegates swift-protocols


    【解决方案1】:

    首先,在Brain 上,您应该使用类,而不是结构。那是因为当你使用 struct 时,将变量传递给另一个会复制,它不会使用相同的引用。并且类只会复制引用。

    这意味着您的 Brain 结构将失去分配给 .delegate = self 的委托

    其次,您需要在第二个 viewController 和第一个上使用相同的实例。像这样:

    在第一个 viewController 上

    var brain = Brain()
    // this one is the one that you will put your "brain.delegate = self"
    

    在第二个 viewController 上,您需要将此变量从第一个 viewController 注入到第二个。那就是在两者上保持相同的实例。这将使委托可调用。

    要使用故事板执行此操作,您将在第一个 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?
    

    【讨论】:

    • 感谢您的回答,我在 struct/class 问题上遇到了错误,并且我明白为什么我需要在两个 ViewController 上使用相同的 Brain 实例,但是如何在我之间转换时注入变量两个通过故事板转场?
    • 我更新了我的答案,哦,为了segue,等一下。
    • 好的,感谢第二个 viewController ?
    • 这里只是声明变量,然后你可以在第二个你想调用的地方调用它。
    【解决方案2】:

    你根本不需要额外的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, newActionValue: 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, newActionValue: 5, isPositive: true)
            self.dismiss(animated: true)
    }
    

    这应该可以完成工作

    【讨论】:

    • 感谢您的回答,但现在代码无法编译,它给了我这个错误 'Non-'@objc' method 'newAction(actualScore:newActionValue:isPositive:)' does not meet '@objc' 协议 'BrainDelegate' 的要求' 我试图将 @objc 注释添加到 newAction 的默认扩展,但它不起作用
    • 您是否在协议声明中添加了@objc 扩展? @objc protocol BrainDelegate ?
    • 是的,我在协议声明之前添加了@objc 注释,这是我唯一使用它的地方
    • @dadamatteo: 哦,明白了,等一下让我更新答案
    • 是的,完美,一切正常,将其标记为答案,谢谢队友
    猜你喜欢
    • 2019-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-29
    • 2012-09-30
    • 1970-01-01
    相关资源
    最近更新 更多