Swift协议扩展调用super报错 如何实现控制器Nib初始化
代码合法性判定
你编写的这段代码不合法,编译报错的核心原因是:super 关键字仅能在具体类的成员实现内部使用,用来沿继承链调用父类的方法/构造器;而协议扩展属于跨类型的全局逻辑注入,不存在明确的类继承上下文,因此编译器不允许在协议扩展内直接调用 super.init,会抛出你看到的 'super' cannot be used outside of class members 错误。
修正实现方案
不要在协议扩展中尝试调用super构造器,利用UIViewController本身公开的指定构造器init(nibName:bundle:)实现逻辑即可,推荐两种常用的实现方式:
方案1:工厂方法实现(最稳定无冲突)
这种写法不会和系统类自带的构造器产生命名冲突,是项目中最常用的实现:
import UIKit public protocol NibInitializable {} extension NibInitializable where Self: UIViewController { /// 默认从和类同名的Nib文件初始化控制器,Nib默认取当前类所在的Bundle public static func instantiateFromNib() -> Self { let nibName = String(describing: Self.self) let bundle = Bundle(for: Self.self) return Self.init(nibName: nibName, bundle: bundle) } }
使用方式:
// 控制器只需要声明遵循协议即可 class ProfileViewController: UIViewController, NibInitializable {} // 初始化时调用工厂方法 let profileVC = ProfileViewController.instantiateFromNib()
方案2:自定义构造器实现
如果偏好直接用构造器初始化,可以给构造器加一个无意义的标签参数避免和系统默认构造器冲突:
import UIKit public protocol NibInitializable { init() } extension NibInitializable where Self: UIViewController { public init(nib: Void = ()) { let nibName = String(describing: Self.self) let bundle = Bundle(for: Self.self) self.init(nibName: nibName, bundle: bundle) } }
使用方式:
class ProfileViewController: UIViewController, NibInitializable {} // 初始化 let profileVC = ProfileViewController(nib: ())
如果需要自定义Nib文件名或者所属Bundle(比如跨模块调用时资源放在独立Bundle中),只需要在对应控制器中重写对应逻辑即可,不需要修改协议默认实现。
内容的提问来源于stack exchange,提问作者Burhanuddin Sunelwala
相关产品推荐
相关产品推荐

