【问题标题】:iOS Swift, with one common method in protocol and two implementations in two ViewControllers, how to decide which ViewControllers method is invoked?iOS Swift,protocol 中一个通用方法,两个 ViewController 中两个 implementation,如何决定调用哪个 ViewControllers 方法?
【发布时间】:2018-09-04 22:02:01
【问题描述】:

我有一个协议

protocol HandleEmbedController: class {
    func printMsg()
}

还有 2 个容器视图和 2 个对应的 ViewControllers

class EnemyBaseVC: UIViewController, HandleEmbedController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    var value1 = ""

    func printMsg(){
        print("printing some embedded message")
    }

} 

class EnemyBase2VC: UIViewController, HandleEmbedController {

    func printMsg() {
        print("enemy base 2 message")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

    }

}

并且都使用协议HandleEmbedController并实现printMsg功能。

在主 ViewController 我有

class HomeBaseVC: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    var handleEmbedController:HandleEmbedController?

    @IBAction func onclick(_ sender: UIButton) {

        handleEmbedController?.printMsg()
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        if (segue.identifier == "embedseg"){
            if let embed = segue.destination as? EnemyBaseVC     {
                self.handleEmbedController = embed
            }
        }

        if (segue.identifier == "embedseg2"){
            if let embed = segue.destination as? EnemyBase2VC     {
                self.handleEmbedController = embed
            }
        }


    }
}

当按钮被点击时,总是EnemyBaseVC方法被调用并打印

printing some embedded message

有没有办法决定调用哪个方法?

更新

【问题讨论】:

  • 问题不在于决定调用哪个方法。调用的方法将是在handleEmbedController 指向的任何类中实现的printMsg。错误不在onclick func 我相信它在if let embed = segue.destination as? EnemyBase2VCif (segue.identifier == "embedseg2")
  • 我的意思是,这两个条件下的代码似乎是正确的。我的意思是,那些ifs 是您的逻辑可能中断的地方。但是错误可能来自故事板中的segue。可以是标识符或目的地类别中的拼写错误。
  • @Gonzo 不错!
  • @Gonzo 我检查了标识符。他们是正确的。当应用程序启动时仅调用 EnemyBaseVC 中的 viewDidLoad()。未调用 EnemyBaseVC2。有没有一种方法可以通过单击按钮以编程方式调用它们
  • @IsankaLakshan 基于我所看到的,当你的主视图控制器被加载时,两者都应该被触发。我会在 EnemyBaseVC viewDidLoad 中放置一个断点,并确保它不会被实例化两次。否则,如果您想借此聊天和分享您的代码,我很乐意看一看,看看发生了什么。

标签: ios swift uiviewcontroller delegates


【解决方案1】:

如果你有两个容器视图,加载时都会触发两个 segue,handleEmbedController 将引用最后加载的一个 ViewController。

如果您有一些逻辑来决定应该引用哪个,那么您可以使用它来决定将引用哪个 ViewController,如下所示:

class HomeBaseVC: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()

}

var handleEmbedController:HandleEmbedController?

//  comes from your decision logic
var decisionMaker: Bool = false

@IBAction func onclick(_ sender: UIButton) {

    handleEmbedController?.printMsg()
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

    if (segue.identifier == "embedseg"),
        let embed = segue.destination as? EnemyBaseVC,
        decisionMaker {
        self.handleEmbedController = embed
    }

    else if (segue.identifier == "embedseg2"),
        let embed = segue.destination as? EnemyBase2VC,
        !decisionMaker {
        self.handleEmbedController = embed
    }
  }
}

请注意,这将在加载时设置 handleEmbedController,如果您需要更复杂的行为,您不妨在 segue 之外的其他地方处理 handleEmbedController 的分配。

由于在这种情况下,您的基础 ViewController 必须与多个对象进行通信,因此您也可以使用通知而不是委托。这样,您可以决定在用户​​点击按钮时发送哪条消息。你的基础 ViewController 看起来像这样

class HomeBaseVC: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    //  comes from your decision logic
    var decisionMaker: Bool = true

    @IBAction func onclick(_ sender: UIButton) {
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "BUTTON_WAS_TAPPED"), object: nil, userInfo: ["decision" : decisionMaker])
    }
}

而敌人的 ViewController 看起来像这样(第二个是相同的,除了要处理的决策值)

class EnemyBaseVC: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "BUTTON_WAS_TAPPED"),
                                           object: nil,
                                           queue: nil) { notification in
                                                if let userInfo = notification.userInfo,
                                                    let decision = userInfo["decision"] as? Bool,
                                                    decision {
                                                        self.printMsg()
                                                }
        }
    }

    var value1 = ""

    private func printMsg(){
        print("printing some embedded message")
    }
}

【讨论】:

  • prepare 方法只调用一次对吗?如果两个容器视图都在主故事板中,则 handleEmbedController 仅具有最后初始化 embedseg 的实例。有什么方法可以将 embed = segue.destination 设置为?按钮点击中的 EnemyBase2VC
  • 感谢您的回答。但是当有 2 个子控制器类时,第二个类中不会调用 viewDidLoad()。
猜你喜欢
  • 1970-01-01
  • 2017-01-17
  • 2023-03-08
  • 1970-01-01
  • 2018-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多