Giter Club home page Giter Club logo

swiftdatastorage's Introduction

SwiftDataStorage

Platforms Swift Package Manager License

This library offers a lightweight property wrapper that can be used for abstracting SwiftData logic.

Table of Contents

  1. Requirements
  2. Installation
  3. Setup
  4. Usage
  5. Examples
  6. Author

Requirements

Platform Minimum Version
iOS 17.0
macOS 14.0
tvOS 17.0
watchOS 10.0

Installation

Swift Package Manager

Swift Package Manager is a tool for managing the distribution of Swift code. It integrates with the Swift build system to automate the process of downloading, compiling, and linking dependencies.

Xcode

To integrate SwiftDataStorage into your Xcode project using Xcode 15 or later, follow these steps:

  1. Open your project in Xcode.
  2. Select File > Swift Packages > Add Package Dependency...
  3. Enter the package repository URL:
https://github.com/JamesSedlacek/SwiftDataStorage.git
  1. Choose the version rule that makes sense for your project.
  2. Select Add Package.

Package.swift

If you are developing a Swift package or have a project that already uses Package.swift, you can add SwiftDataStorage as a dependency:

// swift-tools-version:5.10
import PackageDescription

let package = Package(
    name: "SwiftDataStorage",
    dependencies: [
        .package(url: "https://github.com/JamesSedlacek/SwiftDataStorage.git", branch: "main")
    ],
    targets: [
        .target(
            name: "YourTargetName",
            dependencies: ["SwiftDataStorage"])
    ]
)

Setup

  1. Create any PersistentModel for your project.
@Model
final class MockModel: Identifiable {
    @Attribute(.unique) public let id: UUID
    public var testProperty: String

    init(id: UUID = .init(), _ testProperty: String) {
        self.id = id
        self.testProperty = testProperty
    }
}
  1. Set up your ModelContainer with all of your models.
extension ModelContainer {
    @MainActor
    static let prod: ModelContainer = {
        do {
            return try ModelContainer(for: MockModel.self)
        } catch {
            fatalError("Failed to initialize ModelContainer.")
        }
    }()
}
  1. Inject the ModelContainer into the environment via the .modelContainer modifier.
@main
struct ExampleApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .modelContainer(.prod)
        }
    }
}

Usage

Inject the modelContext from the environment into the ViewModel via .fetch(context:)

struct ContentView: View {
    @Environment(\.modelContext) private var context
    @State private var viewModel: ContentViewModel = .init()

    var body: some View {
        VStack {
            // Add more code here
        }
        .onAppear {
            viewModel.fetch(context: context)
        }
    }
}

Use the @SwiftDataStorage property wrapper to manage your PersistentModel array.
Note - @ObservationIgnored is required to use Property Wrappers when using @Observable macro

@Observable
final class ContentViewModel {
    @ObservationIgnored
    @SwiftDataStorage var models: [MockModel]

    init() {}

    func fetch(context: ModelContext) {
        do {
            try _models.fetch(context: context)
        } catch {
            // TODO: Handle fetch failure
        }
    }
}

Public Functions

/// Fetches objects from the persistent storage based on the specified criteria and updates the internally managed collection.
/// - Parameter context: The context within which the fetch operation should be performed.
/// - Parameter descriptor: The criteria used to fetch objects. Defaults to an empty descriptor indicating no specific filtering.
/// - Throws: An error if the fetch operation fails, allowing calling code to handle fetch-related issues appropriately.
public func fetch(
    context: ModelContext,
    descriptor: FetchDescriptor<T> = .init()
) throws

/// Appends a single object to the persistent storage and the managed collection, if it's not already present.
/// - Parameter object: The object to be appended.
/// Ensures that the operation is performed within the appropriate context and logs a warning if the context is not set.
public func append(_ object: T)

/// Appends multiple objects to the persistent storage and the managed collection, excluding duplicates.
/// - Parameter objectsToAppend: The collection of objects to be appended.
public func append(_ objectsToAppend: [T])

/// Removes a specified object from both the persistent storage and the managed collection.
/// - Parameter object: The object to be removed.
/// Verifies the operation's context and logs a warning if the context is not set.
public func remove(_ object: T)

/// Removes multiple objects from both the persistent storage and the managed collection.
/// - Parameter objectsToRemove: The collection of objects to be removed.
public func remove(_ objectsToRemove: [T])

/// Removes all objects that meet the criteria specified by a predicate from both the persistent storage and the managed collection.
/// - Parameters:
///   - predicate: An optional predicate to filter objects for removal. If nil, all objects in the collection are removed.
///   - includeSubclasses: Indicates whether to include subclasses of `T` in the removal operation. Defaults to true.
/// - Throws: An error if the removal operation fails, allowing for error handling by the caller.
public func removeAll(
    where predicate: Predicate<T>? = nil,
    includeSubclasses: Bool = true
) throws

/// Updates the managed collection of objects to synchronize with the provided collection,
/// ensuring consistency between the persistent storage and the internal state.
/// - Parameter objects: The new collection of objects to be synchronized.
private func update(to objects: [T])

Examples

Example of adding, deleting, and showing model data in a List

struct ContentView: View {
    @Environment(\.modelContext) private var context
    @State private var viewModel: ContentViewModel = .init()

    var body: some View {
        VStack {
            Button("Add Random Model") {
                viewModel.addRandom()
            }
            List(viewModel.models) { model in
                Text(model.testProperty)
                    .swipeActions {
                        Button("Delete", role: .destructive) {
                            viewModel.delete(model)
                        }
                    }
            }
        }
        .onAppear {
            viewModel.fetch(context: context)
        }
    }
}
@Observable
final class ContentViewModel {
    @ObservationIgnored
    @SwiftDataStorage var models: [MockModel]

    init() {}

    func fetch(context: ModelContext) {
        try? _models.fetch(context: context)
    }

    func addRandom() {
        _models.append(.init(UUID().uuidString))
    }

    func delete(_ model: MockModel) {
        _models.remove(model)
    }
}

Author

James Sedlacek, find me on X/Twitter or LinkedIn

swiftdatastorage's People

Contributors

jamessedlacek avatar

Stargazers

James Thang avatar Matthew R. Miller avatar Covalent avatar Ajaya Mati avatar Olijujuan Green avatar Daniel Waylonis avatar Bemol avatar LACHKAR Zakaria avatar David Peak avatar Amar avatar Narcis avatar  avatar Joseph Fischetti avatar Charles Vincent avatar Dave Coleman avatar Simon Breit avatar Nicolas avatar Pablo avatar Jacob Martin avatar Magnus Burton avatar noppe avatar Kyoya Yamaguchi avatar Arturo Diaz avatar Vincent avatar Yubo avatar Michael Samoylov avatar Alessandro Bortoluzzi avatar Akivaev Mark avatar  avatar Marc Maguire avatar Karim Ebrahem avatar Igor Silva avatar Pedro Esli avatar insub avatar Peter Salz avatar Jiong avatar iusn avatar  avatar Pavunraj-Palanisamy avatar  avatar Jonathan Yee avatar Leo Quinteros avatar Miguel Piedrafita avatar Chris Dillard avatar beforeold avatar Gyuri Grell avatar Sandalots avatar 小弟调调 avatar  avatar  avatar Raj H Raval avatar Frederik Winkelsdorf avatar Fabio Fiorita avatar Vladislav Shtefanko avatar Hidde van der Ploeg avatar Federico G. Ramos avatar elGeekalpha avatar Eric Sans avatar Artem F avatar Eren Kundakçı avatar Dimo Hamdy avatar xiguagua avatar Igor Tarasenko avatar Nazarii Tsok avatar Görkem Güclü avatar Dan Murfin avatar Ninja avatar Fabian Gruß avatar Isaque da Silva avatar  avatar

Watchers

 avatar Peter Salz avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.