You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS Swift中协议通用方法多实现时,如何确定调用哪个ViewController的方法?

如何确定调用哪个实现了HandleEmbedController协议的ViewController的方法?

先还原你的代码场景:
你定义了一个协议:

protocol HandleEmbedController: class { 
    func printMsg() 
}

同时有两个容器视图对应的ViewController都实现了这个协议:

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()
    }
}

这个问题的核心是理解Swift中协议的多态特性以及实例引用的指向——具体调用哪个ViewController的printMsg()方法,完全取决于你调用的是哪个实例的方法。下面分几种常见场景给你说明:

1. 直接持有具体ViewController的实例

如果你在代码中直接创建并持有了EnemyBaseVC或EnemyBase2VC的实例,调用哪个实例的printMsg()就会执行对应类的实现:

// 创建EnemyBaseVC实例并调用方法
let enemy1VC = EnemyBaseVC()
enemy1VC.printMsg() // 输出:printing some embedded message

// 创建EnemyBase2VC实例并调用方法
let enemy2VC = EnemyBase2VC()
enemy2VC.printMsg() // 输出:enemy base 2 message

2. 通过协议类型持有实例

如果你的变量声明为HandleEmbedController协议类型,那么实际执行的方法由该变量当前指向的具体实例决定(这就是多态的体现):

// 声明协议类型变量
var embedController: HandleEmbedController

// 让变量指向EnemyBaseVC实例
embedController = EnemyBaseVC()
embedController.printMsg() // 输出:printing some embedded message

// 让变量指向EnemyBase2VC实例
embedController = EnemyBase2VC()
embedController.printMsg() // 输出:enemy base 2 message

3. 从容器视图中获取嵌入的ViewController实例

因为你提到这是容器视图对应的ViewController,通常你会在容器ViewController中管理这些嵌入的子VC。你可以通过两种方式精准调用:

方式一:添加子VC时保留引用

在容器VC中保存每个嵌入VC的实例引用,之后直接调用对应引用的方法:

class ContainerViewController: UIViewController {
    // 保存两个嵌入VC的引用
    private var enemyBaseVC: EnemyBaseVC?
    private var enemyBase2VC: EnemyBase2VC?

    override func viewDidLoad() {
        super.viewDidLoad()
        // 添加第一个嵌入VC到容器
        enemyBaseVC = EnemyBaseVC()
        addChild(enemyBaseVC!)
        enemyBaseVC?.view.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 200)
        view.addSubview(enemyBaseVC!.view)
        enemyBaseVC?.didMove(toParent: self)

        // 添加第二个嵌入VC到容器
        enemyBase2VC = EnemyBase2VC()
        addChild(enemyBase2VC!)
        enemyBase2VC?.view.frame = CGRect(x: 0, y: 200, width: view.frame.width, height: 200)
        view.addSubview(enemyBase2VC!.view)
        enemyBase2VC?.didMove(toParent: self)
    }

    // 调用第一个嵌入VC的方法
    func triggerFirstEmbedMsg() {
        enemyBaseVC?.printMsg()
    }

    // 调用第二个嵌入VC的方法
    func triggerSecondEmbedMsg() {
        enemyBase2VC?.printMsg()
    }
}

方式二:遍历容器的子VC判断类型

如果你没有提前保存引用,可以遍历容器VC的childViewControllers数组,通过类型判断找到目标VC并调用方法:

class ContainerViewController: UIViewController {
    // ... 省略添加子VC的代码 ...

    func callEmbedVCMethod() {
        for childVC in childViewControllers {
            if let targetVC = childVC as? EnemyBaseVC {
                targetVC.printMsg() // 执行EnemyBaseVC的实现
            } else if let targetVC = childVC as? EnemyBase2VC {
                targetVC.printMsg() // 执行EnemyBase2VC的实现
            }
        }
    }
}

总结一下:协议只是定义了方法的规范,实际执行哪个实现完全看你调用的是哪个具体实例的方法——你指向哪个VC的实例,就会执行那个VC里的printMsg()逻辑。

内容的提问来源于stack exchange,提问作者Isanka Lakshan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:50:17