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

Swift项目中如何重写自定义框架类/结构体的部分常量?

解决框架常量部分重写的方案

你的问题核心是Swift不允许同一命名空间下存在同名结构体,直接在子项目里重新定义AppSettings会导致编译冲突。下面提供两种实用方案,实现只重写框架中需要修改的常量:

方案一:协议+默认实现(推荐,符合Swift值类型设计)

把框架中的AppSettings改成协议,通过扩展提供默认值,子项目只需实现协议并覆盖需要修改的常量即可。

框架侧代码

// 定义协议,声明所有需要的常量
public protocol AppSettingsProtocol {
    static var columnCountLandscape: Int { get }
    static var columnCountPortrait: Int { get }
    static var appName: String { get }
    static var imageZoomFactor: CGFloat { get }
    static var version: String { get }
    static var applicationType: String { get }
}

// 扩展协议,提供默认实现
public extension AppSettingsProtocol {
    static var columnCountLandscape: Int { 0 }
    static var columnCountPortrait: Int { 0 }
    static var appName: String { "base" }
    static var imageZoomFactor: CGFloat { 1.0 }
    static var version: String { 
        Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "" 
    }
    static var applicationType: String { "" }
}

// 框架内部定义默认实现的结构体
public struct DefaultAppSettings: AppSettingsProtocol {}

@main
struct MyFramework: App {
    // 全局变量用于子项目注入自定义配置
    public static var currentSettings: AppSettingsProtocol.Type = DefaultAppSettings.self
    
    var body: some Scene {
        WindowGroup {
            switch Self.currentSettings.applicationType {
            case "A": AView()
            case "B": BView()
            case "C": CView()
            default: EmptyView()
            }
        }
    }
}

子项目侧代码

// 实现协议,只重写需要修改的常量
struct CustomAppSettings: AppSettingsProtocol {
    static let appName: String = "MyApp"
    static let columnCountLandscape: Int = 3
    static let applicationType: String = "B"
    // 其他未重写的常量自动使用协议扩展的默认值
}

@main
struct MyApp: App {
    init() {
        // 注入自定义配置
        MyFramework.currentSettings = CustomAppSettings.self
    }
    
    var body: some Scene {
        MyFramework().body
    }
}

方案二:使用类的继承(适合面向对象场景)

由于结构体不支持继承,把框架中的AppSettings改成open类,子项目继承后重写需要的静态属性。

框架侧代码

open class AppSettings {
    open class var columnCountLandscape: Int { 0 }
    open class var columnCountPortrait: Int { 0 }
    open class var appName: String { "base" }
    open class var imageZoomFactor: CGFloat { 1.0 }
    open class var version: String { 
        Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "" 
    }
    open class var applicationType: String { "" }
}

@main
struct MyFramework: App {
    // 全局变量用于子项目替换配置类
    public static var currentSettings: AppSettings.Type = AppSettings.self
    
    var body: some Scene {
        WindowGroup {
            switch Self.currentSettings.applicationType {
            case "A": AView()
            case "B": BView()
            case "C": CView()
            default: EmptyView()
            }
        }
    }
}

子项目侧代码

class CustomAppSettings: AppSettings {
    override class var appName: String { "MyApp" }
    override class var columnCountLandscape: Int { 3 }
    override class var applicationType: String { "B" }
}

@main
struct MyApp: App {
    init() {
        // 替换为自定义配置类
        MyFramework.currentSettings = CustomAppSettings.self
    }
    
    var body: some Scene {
        MyFramework().body
    }
}

额外说明

  • 两种方案都避免了类型冲突,同时保留未修改常量的默认值
  • 如果子项目不需要自定义@main入口,也可以在框架初始化阶段注入自定义配置
  • 优先推荐方案一,符合Swift值类型设计理念,扩展性更强

内容的提问来源于stack exchange,提问作者nirav dinmali

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 04:33:15