Cinder is a compile-time Mach-O registry for Swift. Registrations are emitted
into __DATA,__cinder; no startup hook or central in-memory registration step
is required.
Strings and types use freestanding declaration macros. Actions, instance methods, and class/static methods attach directly to the declaration they register:
import Cinder
#CinderString("root.name", "HomeViewController")
@CinderAction("application.initialize")
func initializeManager() {
Manager.shared.initialize()
}
final class HomeService {}
final class ProfileService {}
final class Dog {
@CinderMethod("dog.eat")
func eat() {
// ...
}
@CinderMethod("dog.prepare")
static func prepare() {
// ...
}
}
#CinderType("services", HomeService.self, multiple: true)
#CinderType("services", ProfileService.self, multiple: true)Another component can discover and execute them without importing the registering component:
let rootName = try Cinder.shared.string(for: "root.name")
let services = try Cinder.shared.types(for: "services")
try Cinder.shared.executeAction(for: "application.initialize")
try Cinder.shared.executeMethod(for: "dog.eat", on: dog)
try Cinder.shared.executeMethod(for: "dog.prepare")For registrations declared with multiple: true, use the corresponding
multiple API:
try Cinder.shared.executeMultipleActions(for: "application.hooks")
try Cinder.shared.executeMultipleMethods(for: "service.prepare")
try Cinder.shared.executeMultipleMethods(for: "service.update", on: service)The macros generate fixed-size binary records with @section and @used.
Action, type, and instance-method records store direct C function pointers in
the section. At runtime Cinder scans every loaded Mach-O image and invokes
those adapters without a startup registration pass. Symbol-based records from
older Cinder builds remain supported.
Keys are single-registration by default. Passing multiple: true allows
independent records in multiple sections to share the same key; results are
returned in image and section order.
Registrations in the application target or a dynamic framework are discovered
automatically. If a component is distributed as a static archive and no symbol
from one of its object files is referenced, the linker may omit that object
file before Cinder can scan it. Such integrations must use the application's
existing whole-archive/force-load strategy (for example -all_load) or package
the registering component as a dynamic framework.