Swift 4.1中fileprivate结构体无法作为默认参数值的解决办法咨询
在Swift 4中使用fileprivate结构体静态属性作为函数默认参数的解决方案
你遇到的问题是Swift 4对默认参数的访问权限限制导致的——当你把fileprivate结构体Defaults的静态属性作为函数默认参数时,编译器会报错,因为Swift 4中默认参数的表达式是在调用者的上下文里求值的,而调用者无法访问fileprivate的结构体成员,所以编译器不允许这种写法。
下面给你几个可行的解决办法:
方案1:调整Defaults结构体的访问权限
如果可以接受Defaults结构体被当前模块内的代码访问,把它的权限从fileprivate改成internal(Swift的默认访问权限就是internal),这样默认参数的表达式就能被正确解析了:
internal struct Defaults { static var BackgroundColor = UIColor.white static var TextColor = UIColor.black static var Title = "Default Title" static var Message = "Default message!" static var AnimationDuration: Double = 0.25 static var Duration: Double = 2 static var Height: CGFloat = 90 static var TitleFont: UIFont = UIFont(name: "SourceSansPro-Semibold", size: Defaults.FontSize)! static var MessageFont: UIFont = UIFont(name: "SourceSansPro-Regular", size: Defaults.FontSize)! static var FontSize: CGFloat = 14 { didSet { TitleFont = TitleFont.withSize(FontSize) MessageFont = MessageFont.withSize(FontSize) } } }
修改后你的原方法就能正常使用了,不用改动函数定义部分。
方案2:在类内部提取私有静态常量(不暴露Defaults)
如果不想让Defaults结构体被外部访问,你可以在类内部定义和Defaults属性对应的私有静态常量,然后用这些常量作为默认参数:
class YourNotificationClass { // 定义私有静态常量存储默认值 private static let defaultTitle = Defaults.Title private static let defaultMessage = Defaults.Message private static let defaultBackgroundColor = Defaults.BackgroundColor private static let defaultTextColor = Defaults.TextColor private static let defaultDuration: Double = Defaults.Duration class func showWithAnimation( _ animationType: AnimationType = .basic(timingFunction: CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)), title: String = defaultTitle, message: String = defaultMessage, backgroundColor: UIColor = defaultBackgroundColor, textColor: UIColor = defaultTextColor, duration: Double = defaultDuration ) { // 方法实现逻辑 } // 保留fileprivate的Defaults结构体用于内部配置 fileprivate struct Defaults { static var BackgroundColor = UIColor.white static var TextColor = UIColor.black static var Title = "Default Title" static var Message = "Default message!" static var AnimationDuration: Double = 0.25 static var Duration: Double = 2 static var Height: CGFloat = 90 static var TitleFont: UIFont = UIFont(name: "SourceSansPro-Semibold", size: Defaults.FontSize)! static var MessageFont: UIFont = UIFont(name: "SourceSansPro-Regular", size: Defaults.FontSize)! static var FontSize: CGFloat = 14 { didSet { TitleFont = TitleFont.withSize(FontSize) MessageFont = MessageFont.withSize(FontSize) } } } }
这里的关键是:类内部的私有静态常量在函数定义的上下文里是可访问的,编译器能正确解析默认参数。
方案3:使用函数重载规避默认参数限制
另一种思路是写一个无参的重载方法,在内部调用带全参数的方法并传入Defaults的属性值,这样完全不用修改Defaults的权限:
class YourNotificationClass { // 无参重载方法,自动使用Defaults的默认值 class func showWithAnimation() { showWithAnimation( .basic(timingFunction: CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)), title: Defaults.Title, message: Defaults.Message, backgroundColor: Defaults.BackgroundColor, textColor: Defaults.TextColor, duration: Defaults.Duration ) } // 带全参数的核心方法 class func showWithAnimation( _ animationType: AnimationType, title: String, message: String, backgroundColor: UIColor, textColor: UIColor, duration: Double ) { // 方法实现逻辑 } fileprivate struct Defaults { // 结构体内容保持不变 static var BackgroundColor = UIColor.white static var TextColor = UIColor.black static var Title = "Default Title" static var Message = "Default message!" static var AnimationDuration: Double = 0.25 static var Duration: Double = 2 static var Height: CGFloat = 90 static var TitleFont: UIFont = UIFont(name: "SourceSansPro-Semibold", size: Defaults.FontSize)! static var MessageFont: UIFont = UIFont(name: "SourceSansPro-Regular", size: Defaults.FontSize)! static var FontSize: CGFloat = 14 { didSet { TitleFont = TitleFont.withSize(FontSize) MessageFont = MessageFont.withSize(FontSize) } } } }
调用者可以选择用showWithAnimation()使用默认值,或者传入自定义参数调用全参数版本,非常灵活。
补充说明
这个限制在Swift 5中有所调整,Swift 5允许默认参数表达式在函数定义的上下文里求值,但Swift 4及更早版本必须遵循调用者上下文的规则,所以上面的方案都是针对Swift 4的适配方案。
内容的提问来源于stack exchange,提问作者Sivakrishna Perla
相关产品推荐
相关产品推荐

