Graph is a semantic database that is used to create data-driven applications.

Overview

Graph

Welcome to Graph

Graph is a semantic database that is used to create data-driven applications.

Material Sample

Features

  • iCloud Support
  • Multi Local & Cloud Graphs
  • Thread Safe
  • Store Any Data Type, Including Binary Data
  • Relationship Modeling
  • Action Modeling For Analytics
  • Model With Graph Theory and Set Theory
  • Asynchronous / Synchronous Search
  • Asynchronous / Synchronous Saving
  • Data-Driven Architecture
  • Data Model Observation
  • Comprehensive Unit Test Coverage
  • Example Projects

Requirements

  • iOS 8.0+ / Mac OS X 10.10+
  • Xcode 8.0+

Communication

  • If you need help, use Stack Overflow. (Tag 'cosmicmind')
  • If you'd like to ask a general question, use Stack Overflow.
  • If you found a bug, and can provide steps to reliably reproduce it, open an issue.
  • If you have a feature request, open an issue.
  • If you want to contribute, submit a pull request.

Installation

Embedded frameworks require a minimum deployment target of iOS 8.

CocoaPods

CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:

$ gem install cocoapods

To integrate Graph's core features into your Xcode project using CocoaPods, specify it in your Podfile:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!

pod 'Graph', '~> 3.1.0'

Then, run the following command:

$ pod install

Carthage

Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.

You can install Carthage with Homebrew using the following command:

$ brew update
$ brew install carthage

To integrate Graph into your Xcode project using Carthage, specify it in your Cartfile:

github "CosmicMind/Graph"

Run carthage update to build the framework and drag the built Graph.framework into your Xcode project.

Changelog

Graph is a growing project and will encounter changes throughout its development. It is recommended that the Changelog be reviewed prior to updating versions.

Samples

The following are samples to see how Graph may be used within your applications.

  • Visit the Samples repo to see example projects using Graph.

Creating an Entity for an ImageCard

An Entity is a model (data) object that represents a person, place, or thing. It may store property values, be a member of groups, and can be tagged.

In the following example, we create an ImageCard view using Material and populate it's properties with an Entity that stores the data for that view.

Material ImageCard

Creating data

let graph = Graph()

let entity = Entity(type: "ImageCard")
entity["title"] = "Graph"
entity["detail"] = "Build Data-Driven Software"
entity["content"] = "Graph is a semantic database that is used to create data-driven applications."
entity["author"] = "CosmicMind"
entity["image"] = UIImage.load(contentsOfFile: "frontier", ofType: "jpg")

graph.sync()

Setting the view's properties

imageCard.toolbar?.title = entity["title"] as? String
imageCard.toolbar?.detail = entity["detail"] as? String
imageCard.imageView?.image = entity["image"] as? UIImage

let contentLabel = UILabel()
contentLabel.text = entity["content"] as? String
imageCard.contentView = contentLabel

let authorLabel = UILabel()
authorLabel.text = entity["author"] as? String
imageCard.bottomBar?.centerViews = [authorLabel]

Searching a list of users in realtime

Using the Search API is incredibly flexible. In the following example, Search is used to create a live search on user names with a dynamic UI provided by Material's SearchBar.

Material SearchBar

Preparing the search criteria

let graph = Graph()

let search = Search<Entity>(graph: graph).for(types: "User").where(properties: "name")

Asynchronously searching graph

search.async { [weak self, pattern = pattern] (users) in

	guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else {
	    return
    }

	var data = [Entity]()

	for user in users {
		if let name = user["name"] as? String {
			let matches = regex.matches(in: name, range: NSRange(location: 0, length: name.utf16.count))

			if 0 < matches.count {
				data.append(user)
			}
		}
	}

	self?.tableView.data = data
}

License

The MIT License (MIT)

Copyright (C) 2019, CosmicMind, Inc. http://cosmicmind.com. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Comments
  • Need help deciding on Better Handling of Object Types

    Need help deciding on Better Handling of Object Types

    Hi again,

    Graph does a great job handling everything I need, except, I'm a closed minded developer who needs every object to be immaculate. Anyways, Referring every object I'm working with as Entity and pass them around is something I can't get my head around it. Maybe I'm seeing it from a wrong perspective (it's highly likely), but I cannot find a good resource on it.

    I tried to overcome this dilemma by introducing custom types based on Entity and simply add properties based on my needs to the Entity based objects. Here is an example:

    
    class MyObject: Entity {
    
      private struct FieldNames {
      static let EntityType = "MyObject"
        struct Properties {
          static let Field1Name = "field1"
          static let Field2Name = "field2"
        }
      }
    
      var Field1: String? {
        return self[FieldNames.Properties.Field1Name] as? String
      }
    
      var Field2: String? {
        return self[FieldNames.Properties.Field2Name] as? String
      }
    }
    
    

    This way I can work with entities in a more civilized manner. I have actually a more complex set of properties and they synchronize with graph with ease but I don't want to get into that for now.

    Now the problem: Because Graph returns Entity objects and they are initialized as Entity I can't downcast them to my own types. It seems obvious, I know. Extending Entity is not an option here because it affects all Entityobjects not just my types.

    Needless to say, all these goes for Relationships too.

    Questions: 1- Is this a good pattern at all? Am I wrong thinking about such solutions and should swallow the pill and work with graphs as they are intended to work? I'm still thinking in pure CoreData mindset which I had control over my object types. (Pattern - AntiPattern)

    2- How can I overcome this dilemma? I was under the impression that I can make custom type converters but apparently I was wrong. How do you think I can make this work?

    3- Is it a good idea to design the object as a composite (I'm not even sure I'm using the right pattern name here) and use the entity as an internal mechanism to return values based on that? Something like this:

    class MyObject {
      private struct FieldNames {
      static let EntityType = "MyObject"
        struct Properties {
          static let Field1Name = "field1"
          static let Field2Name = "field2"
        }
      }
      let entity: Entity!
      init?(entity: Entity){    
        self.entity = entity
        guard entity.type == FieldNames.EntityType else {
          return nil
        }
      }
    
      var Field1: String? {
        return entity[FieldNames.Properties.Field1Name] as? String
      }
    
      var Field2: String? {
        return entity[FieldNames.Properties.Field2Name] as? String
      }
    
    }
    

    Is there any caveat in doing so? Memory leaks maybe? Synchronization?

    help wanted 
    opened by mohpor 18
  • iCloud feature doesn't works for new projects

    iCloud feature doesn't works for new projects

    Just make a new project, turn on iCloud, make an instance of Graph using the cloud init (where is not clear the purpose of the string you have to pass), make a new record and save the db, and finally setup a search, run it and you'll see the returned array is always empty

    Investigate 
    opened by swiftsrl 14
  • Wikipedia links

    Wikipedia links

    Would love to see some wikipedia links to these subjects:

    Relationship Modeling Action Modeling For Analytics Model With Graph Theory and Set Theory Faceted Search API

    Or other good links/books

    enhancement help wanted 
    opened by eonist 12
  • Best way of searching entity.

    Best way of searching entity.

    Hi, first off, I would like to say that I love the concept. I've been using it for a few days and I would like to ask if there is an optimized way that you'd recommend for searching for a specific entity with a specific property. I've been time profiling the app I'm using and for comparing 350 entities that already exist in the Graph, its taking roughly 10 seconds.

    help wanted 
    opened by JARMourato 10
  • Relationship Deletion

    Relationship Deletion

    How can we delete the relationship and their all relationships(subject and object). Seems like when trying to relationship.delete() will not delete its Entities(subject and object).

    question 
    opened by lazarte 9
  • Graph store url

    Graph store url

    Hi, is there any plans for providing a way to pass the graph location when creating ? Imagine that I want to share data between an iOS app and a Today Extension, I would have to use a shared container, which means Graph would have to be located there.

    How could i do that using Graph ?

    help wanted question 
    opened by JARMourato 9
  • Feature Request: Make Entity conforming to Codable or offer a

    Feature Request: Make Entity conforming to Codable or offer a

    Hi all, especially Daniel :)

    I'm in a need including Entity vars in a struct that conforms to Codable (as of Swift 4).

    Not sure if that makes sense in regards to the Graph API philosophy, but to me, that'd be useful as I wouldn't need to remodel the Entity's structure.

    Thanks for Graph anyway - what a decent piece of great software!

    Best wishes,

    Karsten

    question Feature Request Investigate graph 
    opened by karstengresch 8
  • Migrate database from local to cloud with graph

    Migrate database from local to cloud with graph

    i would like to implement the cloud feature of graph. I ve searched on cosmicmind site, here on the repo (looking for wiki), and through the issues (closed). I have just learnt that feature is available, but i did not find any documentation.

    Considering i am already using graph, in local:

    let graph = Graph()
    let entityPfx = "entityPfx"
    let search = Search<Entity>(graph: graph).for(types: entityPfx)
    let results = search.sync()
    

    I would like users could retrieve data from the cloud in case of device upgrade or so. Is there any documentation available in order to implement this? Thank you.

    Referring to https://stackoverflow.com/questions/48667199/migrate-database-from-local-to-cloud-with-graph

    question Investigate graph 
    opened by siideffect 8
  • Multi-threading with Graph

    Multi-threading with Graph

    Hi guys, while testing your library I've made an app and installed crashlytics so I could track errors. I've come across this stack trace a couple of times now :

    Thread : Crashed: com.jarm.testGraph.dataBaseQueue 0 libobjc.A.dylib 0x19938dbd0 objc_msgSend + 16 1 CoreData 0x18444210c -[NSManagedObjectContext(_NSInternalAdditions) _retainedObjectWithID:optionalHandler:withInlineStorage:] + 84 2 CoreData 0x184482f80 -[_NSFaultingMutableSet willReadWithContents:] + 576 3 CoreData 0x184464f1c -[_NSFaultingMutableSet countByEnumeratingWithState:objects:count:] + 44 4 libswiftFoundation.dylib 0x101725848 TFC10Foundation15NSFastGenerator4nextfS0_FT_GSqPSs9AnyObject_ + 80 5 Graph 0x1005f1fa4 specialized ManagedEntity.subscript.getter (ManagedEntity.swift:64) 6 Graph 0x1005f0900 ManagedEntity.subscript.getter (ManagedEntity.swift:63) 7 Graph 0x1005c40c8 Entity.subscript.getter (Entity.swift:87) 8 testGraph 0x100089bd4 PersistanceManager.(createEntryFrom in _31C0B1288B530182F4EB108E0D3B2867)(Entity) -> Entry (PersistanceManager.swift:243)

    I'm using a background thread to get the entity from Graph. So my question is: Is there a recommended way to fetch result from Graph in background threads ? Could it be done concurrently or only serially ?

    Thanks for the help.

    PS: IMHO this library would benefit from a detailed documentation, I don't know if that is on your backlog ;) I'd be happy to contribute to that if you like

    help wanted 
    opened by JARMourato 7
  • Maybe a bug, But more likely something im doing wrong

    Maybe a bug, But more likely something im doing wrong

    private func internalSelect(x: RedBlackNode<Key, Value>, order: Int) -> RedBlackNode<Key, Value> {
        validateOrder(order)
        var r: Int = x.left.order + 1
        if order == r {
            return x
        } else if order < r {
            return internalSelect(x.left, order: order)
        }
        return internalSelect(x.right, order: order - r)
    }
    

    I keep getting " fatal error: unexpectedly found nil while unwrapping an Optional value (lldb) "

    Seems to happen after hitting this line of code in my project var randomWordFromWords = graph.search(Entity: "Word")[randomNumber()]

    screen shot 2015-09-03 at 10 59 02 am bug question 
    opened by NinjaIshere 5
  • ManagedNode.swift - breaking change using XCode 10.2 Swift 5 Compiler

    ManagedNode.swift - breaking change using XCode 10.2 Swift 5 Compiler

    I've set SWIFT_VERSION to 4.2 for the Graph pod but when compiling my workspace I get the following error in ManagedNode.swift line 55: Incorrect argument label in call (have 'stringInterpolationSegment:', expected '_cocoaString:')

    The code in question is below. Apple documentation indicates that String(stringInterpolationSegment: should not be called directly. I tried amending the parameter as the error suggested but that just caused a runtime crash. I'm not clear what this code is trying to achieve exactly so can't recommend how to fix it. There's obviously something subtle going on as otherwise why not just use "(self.nodeClass)" instead? ( I tried changing the code to that too but caused runtime crash too).

            guard let moc = managedObjectContext else {
                fatalError("[Graph Error: Cannot obtain permanent objectID]")
            }
            
            var result: String?
            moc.performAndWait { [unowned self, unowned moc] in
                do {
                    try moc.obtainPermanentIDs(for: [self])
                } catch let e as NSError {
                    fatalError("[Graph Error: Cannot obtain permanent objectID - \(e.localizedDescription)]")
                }
                result = String(stringInterpolationSegment: self.nodeClass) + self.type + self.objectID.uriRepresentation().lastPathComponent
            }
            return result!
        }
    Investigate graph 
    opened by muzoman 3
  • Deprecated keys

    Deprecated keys

    Hi,

    I found this library by chance, and it seems that it may be pretty helpful. I'm just starting, but I noticed that there are several deprecations:

    • NSPersistentStoreUbiquitousTransitionType
    • NSPersistentStoreUbiquitousContentNameKey
    • NSPersistentStoreDidImportUbiquitousContentChanges
    • NSPersistentStoreUbiquitousTransitionTypeKey

    Xcode just tells "was deprecated in iOS 10.0: Please see the release notes and Core Data documentation." However, I did some googling and did not find anything that would give me an indication about how to replace those keys.

    So, I'd like to report this to you, assuming that you know better by far than me what this might mean, and how to handle it...

    • Hardy
    opened by innoreq 0
  • Comparisons in .where cause crash

    Comparisons in .where cause crash

    Hi 👋

    I'm facing a weird issue, when I run this code:

    // initial.id is a UUID
    
    let search = Search<Entity>(graph: Globals.graph).where(
        .type("Customers", using: &&)
            && "id" == initial.id as CVarArg // <- Is it the good way?
    )
    

    This causes a crash (here is the crashlog: https://pastebin.com/uk6em3p1).

    But if I run this code, it works:

    let search = Search<Entity>(graph: Globals.graph).where(.type("Customers"))
    let entity = search.sync().filter {
        $0["id"] as! UUID == initial.id
    }
    

    Am I doing something wrong with the new API or is it a library issue? Thanks!

    opened by vlourme 0
  • transformable properties issue

    transformable properties issue

    Hi, im using the latest stable version on graph im my project (i also tried development branch but the issue is there too). Since i updated to iOS 13, i am experiencing what looks like a bad error, which i will post here:

    [error] fault: One or more models in this application are using transformable properties with transformer names that are either unset, or set to NSKeyedUnarchiveFromDataTransformerName. Please switch to using "NSSecureUnarchiveFromData" or a subclass of NSSecureUnarchiveFromDataTransformer instead. At some point, Core Data will default to using "NSSecureUnarchiveFromData" when nil is specified, and transformable properties containing classes that do not support NSSecureCoding will become unreadable.

    CoreData: fault: One or more models in this application are using transformable properties with transformer names that are either unset, or set to NSKeyedUnarchiveFromDataTransformerName. Please switch to using "NSSecureUnarchiveFromData" or a subclass of NSSecureUnarchiveFromDataTransformer instead. At some point, Core Data will default to using "NSSecureUnarchiveFromData" when nil is specified, and transformable properties containing classes that do not support NSSecureCoding will become unreadable.

    2020-01-03 18:39:45.842073+0100 APPNAME[50600:5957542] [error] CoreData: One or more models in this application are using transformable properties with transformer names that are either unset, or set to NSKeyedUnarchiveFromDataTransformerName. Please switch to using "NSSecureUnarchiveFromData" or a subclass of NSSecureUnarchiveFromDataTransformer instead. At some point, Core Data will default to using "NSSecureUnarchiveFromData" when nil is specified, and transformable properties containing classes that do not support NSSecureCoding will become unreadable.

    Now some specific error: these errors are related to specific graph classes.

    CoreData: warning: Property 'object' on Entity 'ManagedRelationshipProperty' is using nil or an insecure NSValueTransformer. Please switch to using "NSSecureUnarchiveFromData" or a subclass of NSSecureUnarchiveFromDataTransformer instead.

    CoreData: warning: Property 'object' on Entity 'ManagedEntityProperty' is using nil or an insecure NSValueTransformer. Please switch to using "NSSecureUnarchiveFromData" or a subclass of NSSecureUnarchiveFromDataTransformer instead.

    CoreData: warning: Property 'object' on Entity 'ManagedActionProperty' is using nil or an insecure NSValueTransformer. Please switch to using "NSSecureUnarchiveFromData" or a subclass of NSSecureUnarchiveFromDataTransformer instead.

    I have no idea on how to solve this, and where to start, but it looked like a "Hey, you need to fix me asap or i can break your app and make it unasable". Hope you can address this in the development branch you currently are, waiting for a response from you and keep up the good work, graph is awesome.

    opened by siideffect 9
  • ERROR GRAPH CANCEL ROW IN LIST

    ERROR GRAPH CANCEL ROW IN LIST

    func cancella(at offset: IndexSet) {
            guard let intindex = Array(offset).first else { return }
            let id = dm.Storage[intindex].properties["id"] as? String ?? ""
            DataManager.Shared.cancellaPosto(id)
        }
    
    func cancellaPosto(_ ID: String) {
            let operazioneSearch = Search<Entity>(graph: DB).where(.type("Posti") && "id" == ID)
            let operazione =  operazioneSearch.sync(completion: nil)
            
            if let opeDaCanc = operazione.first {
                opeDaCanc.delete()
                if let index = Storage.firstIndex(of: opeDaCanc) {
                    self.Storage.remove(at: index)
                    self.objectWillChange.send()
                }
            }
    
            DB.async {(Bool, error) in
                if let e = error {
                    print(e.localizedDescription)
                }
            }
        }
    

    Fatal error: [Graph Error: Cannot obtain permanent objectID]: file /Users/schulz/Desktop/POI MapNote/POI MapNote/Graph/ManagedNode.swift, line 40 2019-12-09 15:53:14.847221+0100 Simple List[48128:2685330] Fatal error: [Graph Error: Cannot obtain permanent objectID]: file /Users/schulz/Desktop/POI MapNote/POI MapNote/Graph/ManagedNode.swift, line 40

    help wanted Investigate graph 
    opened by schulz89sp 7
  • New (2018) API Changes: ' has no member 'for'"">

    New (2018) API Changes: "Value of type 'Search' has no member 'for'"

    Hi all,

    when switching a project to Swift 5, I upgraded to Graph 3.1.1 (from 2.2.2 and now I get complaints like):

    "Value of type 'Search' has no member 'for'"

    As the Graph examples and documentation still use examples with 'for', I suggest upgrading the documentation to the new API.

    help wanted graph 
    opened by karstengresch 1
Releases(3.1.1)
Owner
Cosmicmind
Build Dreams Together
Cosmicmind
Aplikasi iOS To Do List dengan Storyboard & Local CoreData (Database Xcode)

ToDoList Aplikasi iOS ToDoList adalah sebuah aplikasi CRUD sederhana berbasis iOS yang digunakan untuk membuat sebuah list item. Aplikasi ini dibuat m

DK 7 Aug 1, 2022
JSON to Core Data and back. Swift Core Data Sync.

Notice: Sync was supported from it's creation back in 2014 until March 2021 Moving forward I won't be able to support this project since I'm no longer

Nes 2.5k Dec 31, 2022
Core Data Generator (CDG for short) is a framework for generation (using Sourcery) of Core Data entities from plain structs/classes/enums.

Core Data Generator Introduction Features Supported platforms Installation CDG Setup RepositoryType ModelType DataStoreVersion MigrationPolicy Basic U

Lotusflare 18 Sep 19, 2022
Super awesome Swift minion for Core Data (iOS, macOS, tvOS)

⚠️ Since this repository is going to be archived soon, I suggest migrating to NSPersistentContainer instead (available since iOS 10). For other conven

Marko Tadić 306 Sep 23, 2022
A powerful and elegant Core Data framework for Swift.

A powerful and elegant Core Data framework for Swift. Usage Beta version. New docs soon... Simple do that: let query = persistentContainer.viewContext

null 782 Nov 6, 2022
CloudCore is a framework that manages syncing between iCloud (CloudKit) and Core Data written on native Swift.

CloudCore CloudCore is a framework that manages syncing between iCloud (CloudKit) and Core Data written on native Swift. Features Leveraging NSPersist

deeje cooley 123 Dec 31, 2022
Unleashing the real power of Core Data with the elegance and safety of Swift

Unleashing the real power of Core Data with the elegance and safety of Swift Dependency managers Contact Swift 5.4: iOS 11+ / macOS 10.13+ / watchOS 4

John Estropia 3.7k Jan 9, 2023
JSQCoreDataKit - A swifter Core Data stack

JSQCoreDataKit A swifter Core Data stack About This library aims to do the following: Encode Core Data best practices, so you don't have to think "is

Jesse Squires 596 Dec 3, 2022
JustPersist is the easiest and safest way to do persistence on iOS with Core Data support out of the box.

JustPersist JustPersist is the easiest and safest way to do persistence on iOS with Core Data support out of the box. It also allows you to migrate to

Just Eat 167 Mar 13, 2022
QueryKit, a simple type-safe Core Data query language.

QueryKit QueryKit, a simple type-safe Core Data query language. Usage QuerySet<Person>(context, "Person")

QueryKit 1.5k Dec 20, 2022
A minimalistic, thread safe, non-boilerplate and super easy to use version of Active Record on Core Data.

Skopelos A minimalistic, thread-safe, non-boilerplate and super easy to use version of Active Record on Core Data. Simply all you need for doing Core

Alberto De Bortoli 235 Sep 9, 2022
HitList is a Swift App shows the implementation of Core Data.

HitList HitList is a Swift App shows the implementation of Core Data. It is the demo app of Ray Wenderlich's tech blog. For details please reference G

Kushal Shingote 2 Dec 9, 2022
A synchronization framework for Core Data.

Core Data Ensembles Author: Drew McCormack Created: 29th September, 2013 Last Updated: 15th February, 2017 Ensembles 2 is now available for purchase a

Drew McCormack 1.6k Dec 6, 2022
Core Data code generation

mogenerator Visit the project's pretty homepage. Here's mogenerator's elevator pitch: mogenerator is a command-line tool that, given an .xcdatamodel f

Wolf Rentzsch 3k Dec 30, 2022
Super Awesome Easy Fetching for Core Data!

MagicalRecord In software engineering, the active record pattern is a design pattern found in software that stores its data in relational databases. I

Magical Panda Software 10.9k Dec 29, 2022
A type-safe, fluent Swift library for working with Core Data

Core Data Query Interface (CDQI) is a type-safe, fluent, intuitive library for working with Core Data in Swift. CDQI tremendously reduces the amount o

null 31 Oct 26, 2022
The Big Nerd Ranch Core Data Stack

BNR Core Data Stack The BNR Core Data Stack is a small Swift framework that makes it both easier and safer to use Core Data. A better fetched results

Big Nerd Ranch 561 Jul 29, 2022
100% Swift Simple Boilerplate Free Core Data Stack. NSPersistentContainer

DATAStack helps you to alleviate the Core Data boilerplate. Now you can go to your AppDelegate remove all the Core Data related code and replace it wi

Nes 216 Jan 3, 2023
Example repo of working with Core Data in a SwiftUI application

CoreData in SwiftUI This repository serves many purpose. But mostly so I can experiment with Core Data in SwiftUI, and also so I can use it show my ap

Donny Wals 4 Jan 30, 2022