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

Swift Macro中自定义协议的声明位置及@ServiceProvidable实现问询

Swift Macro自定义协议的存放位置与实现方案

先说核心结论:自定义协议(比如你例子里的ServiceProvidable)必须放在主应用项目(或者主项目能访问的公共模块)里,绝对不能放在Macro Package中。

为什么不能放Macro Package?

Macro Package是编译期的工具代码,它的作用只是生成代码,不会被打包进最终App。而且主项目是依赖Macro Package的,反向依赖不成立——如果协议放在Macro Package里,主项目编译时根本找不到这个协议的定义,宏生成的extension ViewControllerWrapper: ServiceProvidable代码会直接报错。

具体实现步骤

1. 先在主项目定义所有需要的协议和类型

把ServiceProvidable、ServiceProviderProtocol、ServiceProvider这些都写在主项目里(或者抽成主项目依赖的Core公共模块),因为宏生成的代码要直接引用它们:

// 主项目/Core模块中定义
protocol ServiceProviderProtocol {
    // 这里写服务提供者需要的方法/属性
}

class ServiceProvider: ServiceProviderProtocol {
    // 实现协议逻辑
}

protocol ServiceProvidable {
    var service: ServiceProviderProtocol { get }
}

2. 在Macro Package中实现@ServiceProvidable宏

Macro里只需要负责生成遵循协议的扩展代码就行,不用关心协议的具体实现,只要保证生成的代码能在主项目中编译通过:

// Macro Package中的宏实现
import SwiftSyntax
import SwiftSyntaxMacros
import SwiftSyntaxBuilder

public struct ServiceProvidableMacro: MemberMacro {
    public static func expansion(
        of node: AttributeSyntax,
        providingMembersOf declaration: some DeclGroupSyntax,
        in context: some MacroExpansionContext
    ) throws -> [DeclSyntax] {
        // 生成对应类的扩展代码
        return [
            """
            extension \(declaration.name): ServiceProvidable {
                var service: ServiceProviderProtocol {
                    guard let serviceProvider = (UIApplication.shared.delegate as? AppDelegate)?.serviceProvider else {
                        return ServiceProvider()
                    }
                    return serviceProvider
                }
            }
            """
        ]
    }
}

// 注册宏
@main
struct ServiceProvidableMacroPlugin: CompilerPlugin {
    let providingMacros: [Macro.Type] = [
        ServiceProvidableMacro.self
    ]
}

3. 在主项目中使用宏

主项目添加Macro Package依赖后,直接给目标类标记宏即可:

@ServiceProvidable
class ViewControllerWrapper {
    // 类的原有代码
}

额外注意点

  • 宏生成代码里引用的AppDelegate、UIApplication这些,都是主项目里的类型,只要主项目能访问到就没问题。
  • 如果后续要重构,把协议和服务类抽成公共模块,只要主项目和Macro Package都依赖这个公共模块就行——Macro只需要知道这些类型的名称,不需要知道具体实现逻辑。

内容的提问来源于stack exchange,提问作者SOWOL KIM

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 15:47:15