У меня возник вопрос при изучении Swift Macros.
Если определенный тип хочет соответствовать специальному протоколу в макросах Swift, следует ли объявить этот специальный протокол в пакете макросов? Или это можно объявить в основном проекте приложения?
Например, если макрос @ServiceProvidable приводит определенный класс в соответствие с протоколом ServiceProvidable и расширяет код вычисляемым свойством, как это следует реализовать?
@ServiceProvidable
class ViewControllerWrapper {
}
// Expanding a macro
class ViewControllerWrapper { }
extension ViewControllerWrapper: ServiceProvidable {
var service: ServiceProviderProtocol {
guard
let serviceProvider = (UIApplication.shared.delegate as? AppDelegate)?.serviceProvider
else { return ServiceProvider() }
return serviceProvider
}
}





При объявлении макроса необходимо указать соответствия, которые обеспечивает макрос. например
@attached(extension, conformances: FooProtocol) // You need to be able to say "FooProtocol" here
public macro MyMacro() = #externalMacro(module: "SomeImplementationModule", type: "MyMacro")
Следовательно, протокол должен быть объявлен в модуле, к которому может получить доступ приведенный выше код, то есть либо в том же модуле, что и приведенный выше код, либо в одной из его зависимостей. Обычно я просто помещаю его рядом с объявлением макроса.
@attached(extension, conformances: FooProtocol)
public macro MyMacro() = #externalMacro(module: "SomeImplementationModule", type: "MyMacro")
public protocol FooProtocol {
func foo()
}
Обратите внимание: это не тот модуль, в котором вы реализуете макрос.
Вам следует реализовать макрос в другом модуле (в приведенном выше примере в модуле под названием «SomeImplementationModule»), созданном с использованием .macro(...) вместо .target(...) в Package.swift.
Вот пример реализации:
enum MyMacro: ExtensionMacro {
static func expansion(
of node: AttributeSyntax,
attachedTo declaration: some DeclGroupSyntax,
providingExtensionsOf type: some TypeSyntaxProtocol,
conformingTo protocols: [TypeSyntax],
in context: some MacroExpansionContext
) throws -> [ExtensionDeclSyntax] {
let name = declaration.as(ClassDeclSyntax.self)!.name
return [
try ExtensionDeclSyntax("extension \(name): FooProtocol") {
"""
public func foo() { print("example implementation") }
"""
}
]
}
}
@main
struct MyMacroPlugin: CompilerPlugin {
let providingMacros: [Macro.Type] = [
MyMacro.self
]
}
@SOWOLKIM Если вы говорите о (Swift)-пакетах, это не обязательно должно быть так (но часто так и есть). теоретически пакет может иметь только реализацию макроса и ничего больше. Объявление макроса (и, следовательно, объявление протокола) может находиться в другом проекте пакета/Xcode.
спасибо! Следовательно, протокол и его реализация (расширение протокола) должны быть включены в пакет макросов. верно?