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
相关产品推荐
相关产品推荐

