A lightweight Swift library for embedding JSON, YAML and text resources with automatic caching and Swift 6 concurrency support.
- π― Simple API - Clean property wrapper and computed property syntax
- π¦ JSON Support - Built-in JSON decoding
- π YAML Support - Full YAML decoding via Yams
- π Text Support - Load plain text files as strings
- π Type Safe - Compile-time type checking with Decodable
- β‘ Automatic Caching - Resources cached after first load
- π Swift 6 Ready - No concurrency warnings with static properties
- π± Cross-Platform - Works on iOS, macOS, tvOS, watchOS
Add to your Package.swift
:
dependencies: [
.package(url: "https://github.com/botforge-pro/swift-embed.git", from: "1.5.0")
]
SwiftEmbed provides three ways to load resources:
Best for static configuration and avoids Swift 6 concurrency warnings:
import SwiftEmbed
struct AppConfig {
// Clean syntax, no Swift 6 warnings, automatic caching
static var config: Config {
Embedded.getJSON(Bundle.main, path: "Resources/config.json")
}
static var users: [User] {
Embedded.getJSON(Bundle.main, path: "Resources/users.json")
}
static var template: String {
Embedded.getText(Bundle.main, path: "Resources/template.html")
}
}
// Usage
let apiURL = AppConfig.config.apiURL // Loaded and cached on first access
let userCount = AppConfig.users.count // Retrieved from cache
For instance properties in classes/structs:
import SwiftEmbed
struct MyApp {
@Embedded.JSON(Bundle.main, path: "Resources/users.json")
var users: [User]
@Embedded.YAML(Bundle.main, path: "Config/settings.yaml")
var config: Config
@Embedded.Text(Bundle.main, path: "Resources/template.html")
var htmlTemplate: String
}
For immediate use or dynamic loading:
import SwiftEmbed
// Load and decode JSON
let users = Embedded.getJSON(Bundle.main, path: "users.json", as: [User].self)
// Load and decode YAML
let config = Embedded.getYAML(Bundle.main, path: "config.yaml", as: Config.self)
// Load plain text
let template = Embedded.getText(Bundle.main, path: "template.html")
All methods use an internal cache powered by NSCache
:
- Resources are loaded from disk only once
- Subsequent accesses return cached values
- Memory-safe with automatic purging under pressure
- Thread-safe for concurrent access
Perfect for loading test data:
import Testing
import SwiftEmbed
@Suite("API Tests")
struct APITests {
struct TestCase: Decodable {
let input: String
let expected: String
}
// Load test data once, cached for all test runs
static var testCases: [TestCase] {
Embedded.getJSON(Bundle.module, path: "TestData/url_tests.json")
}
@Test("URL Validation", arguments: testCases)
func testURLs(testCase: TestCase) {
// Test implementation
}
}
Place your resource files in your target:
MyApp/
βββ Sources/
β βββ MyApp/
β βββ MyClass.swift
βββ Resources/
βββ data.json
βββ config.yaml
For Swift packages, ensure resources are declared in Package.swift
:
.target(
name: "MyApp",
resources: [
.copy("Resources") // Use .copy() to preserve directory structure
// .process() will flatten the directory structure
]
)
Important: Always use .copy()
instead of .process()
to preserve your directory structure. The .process()
rule will flatten directories and may cause resource loading to fail.
SwiftEmbed is fully compatible with Swift 6's strict concurrency checking:
// β
No warnings - computed property approach
struct MyConfig {
static var settings: Settings {
Embedded.getJSON(Bundle.module, path: "config.json")
}
}
// β
No warnings - static let with direct call
struct MyData {
static let data = Embedded.getJSON(Bundle.module, path: "data.json", as: DataModel.self)
}
// β οΈ Warning with property wrapper on static var
struct BadExample {
@Embedded.JSON(Bundle.module, path: "config.json")
static var config: Config // Swift 6 warning: static var not concurrency-safe
}
- Swift 6.0+
- iOS 15.0+ / macOS 12.0+ / tvOS 15.0+ / watchOS 8.0+