{"id":951,"url":"https://github.com/tadija/AERecord","last_synced_at":"2025-08-06T14:32:52.606Z","repository":{"id":22948113,"uuid":"26297599","full_name":"tadija/AERecord","owner":"tadija","description":"Super awesome Swift minion for Core Data (iOS, macOS, tvOS)","archived":false,"fork":false,"pushed_at":"2018-09-18T20:50:43.000Z","size":355,"stargazers_count":302,"open_issues_count":5,"forks_count":55,"subscribers_count":22,"default_branch":"master","last_synced_at":"2024-11-30T17:40:48.346Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tadija.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-11-07T01:08:26.000Z","updated_at":"2024-08-08T03:33:31.000Z","dependencies_parsed_at":"2022-08-21T02:20:54.387Z","dependency_job_id":null,"html_url":"https://github.com/tadija/AERecord","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tadija%2FAERecord","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tadija%2FAERecord/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tadija%2FAERecord/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tadija%2FAERecord/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tadija","download_url":"https://codeload.github.com/tadija/AERecord/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228915455,"owners_count":17991409,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-01-05T20:15:35.382Z","updated_at":"2024-12-09T15:30:48.796Z","avatar_url":"https://github.com/tadija.png","language":"Swift","funding_links":[],"categories":["Core Data","Libs","UI [🔝](#readme)","Swift"],"sub_categories":["Linter","Other free courses","UI","Data Management"],"readme":"[![Swift 4.2](https://img.shields.io/badge/Swift-4.2-orange.svg?style=flat)](https://swift.org)\n[![Platforms iOS | watchOS | tvOS | macOS](https://img.shields.io/badge/Platforms-iOS%20%7C%20watchOS%20%7C%20tvOS%20%7C%20macOS-lightgray.svg?style=flat)](http://www.apple.com)\n[![CocoaPods](https://img.shields.io/cocoapods/v/AERecord.svg?style=flat)](https://cocoapods.org/pods/AERecord)\n[![Carthage](https://img.shields.io/badge/Carthage-compatible-brightgreen.svg?style=flat)](https://github.com/Carthage/Carthage)\n[![Swift Package Manager](https://img.shields.io/badge/SPM-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager)\n[![License MIT](https://img.shields.io/badge/License-MIT-lightgrey.svg?style=flat)](https://github.com/tadija/AERecord/blob/master/LICENSE)\n\n\u003e ⚠️ Since this repository is going to be archived soon, I suggest migrating to [NSPersistentContainer](https://developer.apple.com/documentation/coredata/nspersistentcontainer) instead (available since iOS 10).\n\u003e For other convenience helpers, beside managing stack, I'm currently just using [this](https://gist.github.com/tadija/6003830264d67a87193ff0c3d20373e7).\n\n# AERecord\n**Super awesome Swift minion for Core Data (iOS, macOS, tvOS)**\n\n\u003e I made this for personal use, but feel free to use it or contribute.\n\u003e For more examples check out [Sources](Sources) and [Tests](Tests).\n\n## Index\n- [Intro](#intro)\n- [Features](#features)\n- [Usage](#usage)\n    - [Create Core Data stack](#create-core-data-stack)\n    - [Context operations](#context-operations)\n    - [Easy Queries](#easy-queries)\n        - [General](#general)\n        - [Create](#create)\n        - [Find first](#find-first)\n        - [Find all](#find-all)\n        - [Delete](#delete)\n        - [Count](#count)\n        - [Distinct](#distinct)\n        - [Auto increment](#auto-increment)\n        - [Turn managed object into fault](#turn-managed-object-into-fault)\n        - [Batch update](#batch-update)\n- [Installation](#installation)\n- [License](#license)\n\n## Intro\n\n[AECoreDataUI](https://github.com/tadija/AECoreDataUI) was previously part of **AERecord**, so you may want to check that also.\n\nWhy do we need yet another one Core Data wrapper? You tell me!  \nInspired by many different (spoiler alert) **magical** solutions, I wanted something which combines complexity and functionality just about right.\nAll that boilerplate code for setting up of Core Data stack, passing the right `NSManagedObjectContext` all accross the project and different threads, not to mention that boring `NSFetchRequest` boilerplates for any kind of creating or querying the data - should be more simple with this.\n\n## Features\n- Create default or custom Core Data stack **(or more stacks)** easily accessible from everywhere\n- Have **[main and background contexts](http://floriankugler.com/2013/04/29/concurrent-core-data-stack-performance-shootout/)**, always **in sync**, but don't worry about it\n- [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) data in many ways with **generic one liners**\n- **iCloud** support\n- Covered with **unit tests**\n- Covered with inline docs\n\n## Usage\n\nYou may see [this demo project](https://github.com/tadija/AECoreDataDemo) for example.\n\n### Create Core Data stack\nAlmost everything in `AERecord` is made with 'optional' parameters (which have default values if you don't specify anything).  \nSo you can load (create if doesn't already exist) CoreData stack like this:\n\n```swift\ndo {\n    try AERecord.loadCoreDataStack()\n} catch {\n    print(error)\n}\n```\n\nor like this:\n\n```swift\nlet myModel: NSManagedObjectModel = AERecord.modelFromBundle(for: MyClass.self)\nlet myStoreType = NSInMemoryStoreType\nlet myConfiguration = ...\nlet myStoreURL = AERecord.storeURL(for: \"MyName\")\nlet myOptions = [NSMigratePersistentStoresAutomaticallyOption : true]\ndo {\n    try AERecord.loadCoreDataStack(managedObjectModel: myModel, storeType: myStoreType, configuration: myConfiguration, storeURL: myStoreURL, options: myOptions)\n} catch {\n    print(error)\n}\n```\n\nor any combination of these.\n\nIf for any reason you want to completely remove your stack and start over (separate demo data stack for example) you can do it as simple as this:\n\n```swift\ndo {\n    try AERecord.destroyCoreDataStack() // destroy default stack\n} catch {\n    print(error)\n}\n\ndo {\n    let demoStoreURL = AERecord.storeURL(for: \"Demo\")\n    try AERecord.destroyCoreDataStack(storeURL: demoStoreURL) // destroy custom stack\n} catch {\n    print(error)\n}\n```\n\nSimilarly you can delete all data from all entities (without messing with the stack) like this:\n\n```swift\nAERecord.truncateAllData()\n```\n\n### Context operations\nContext for current thread (`Context.default`) is used if you don't specify any (all examples below are using `Context.default`).\n\n```swift\n// get context\nAERecord.Context.main // get NSManagedObjectContext for main thread\nAERecord.Context.background // get NSManagedObjectContext for background thread\nAERecord.Context.default // get NSManagedObjectContext for current thread\n\n// execute NSFetchRequest\nlet request = ...\nlet managedObjects = AERecord.execute(fetchRequest: request) // returns array of objects\n\n// save context\nAERecord.save() // save default context\nAERecord.saveAndWait() // save default context and wait for save to finish\n\n// turn managed objects into faults (you don't need this often, but sometimes you do)\nlet objectIDs = ...\nAERecord.refreshObjects(with: [objectIDs], mergeChanges: true) // turn objects for given IDs into faults\nAERecord.refreshRegisteredObjects(mergeChanges: true) // turn all registered objects into faults\n```\n\n### Easy Queries\nEasy querying helpers are created as `NSManagedObject` extension.  \nAll queries are called on generic `NSManagedObject`, and `Context.default` is used if you don't specify any (all examples below are using `Context.default`). All finders have optional parameter for `NSSortDescriptor` which is not used in these examples.\nFor even more examples check out unit tests.\n\n#### General\nIf you need custom `NSFetchRequest`, you can use `createPredicate(with:)` and `createFetchRequest(predicate:sortdDescriptors:)`, tweak it as you wish and execute with `AERecord`.\n\n```swift\n// create request for any entity type\nlet attributes = ...\nlet predicate = NSManagedObject.createPredicate(with: attributes)\nlet sortDescriptors = ...\nlet request = NSManagedObject.createFetchRequest(predicate: predicate, sortDescriptors: sortDescriptors)\n\n// set some custom request properties\nrequest.someProperty = someValue\n\n// execute request and get array of entity objects\nlet managedObjects = AERecord.execute(fetchRequest: request)\n```\n\nOf course, all of the often needed requests for creating, finding, counting or deleting entities are already there, so just keep reading.\n\n#### Create\n```swift\nNSManagedObject.create() // create new object\n\nlet attributes = ...\nNSManagedObject.create(with: attributes) // create new object and sets it's attributes\n\nNSManagedObject.firstOrCreate(with: \"city\", value: \"Belgrade\") // get existing object (or create new if it doesn't already exist) with given attribute\n\nlet attributes = ...\nNSManagedObject.firstOrCreate(with: attributes) // get existing object (or create new if it doesn't already exist) with given attributes\n```\n\n#### Find first\n```swift\nNSManagedObject.first() // get first object\n\nlet predicate = ...\nNSManagedObject.first(with: predicate) // get first object with predicate\n\nNSManagedObject.first(with: \"bike\", value: \"KTM\") // get first object with given attribute name and value\n\nlet attributes = ...\nNSManagedObject.first(with: attributes) // get first object with given attributes\n\nNSManagedObject.first(orderedBy: \"speed\", ascending: false) // get first object ordered by given attribute name\n```\n\n#### Find all\n```swift\nNSManagedObject.all() // get all objects\n\nlet predicate = ...\nNSManagedObject.all(with: predicate) // get all objects with predicate\n\nNSManagedObject.all(with: \"year\", value: 1984) // get all objects with given attribute name and value\n\nlet attributes = ...\nNSManagedObject.all(with: attributes) // get all objects with given attributes\n```\n\n#### Delete\n```swift\nlet managedObject = ...\nmanagedObject.delete() // delete object (call on instance)\n\nNSManagedObject.deleteAll() // delete all objects\n\nNSManagedObject.deleteAll(with: \"fat\", value: true) // delete all objects with given attribute name and value\n\nlet attributes = ...\nNSManagedObject.deleteAll(with: attributes) // delete all objects with given attributes\n\nlet predicate = ...\nNSManagedObject.deleteAll(with: predicate) // delete all objects with given predicate\n```\n\n#### Count\n```swift\nNSManagedObject.count() // count all objects\n\nlet predicate = ...\nNSManagedObject.count(with: predicate) // count all objects with predicate\n\nNSManagedObject.count(with: \"selected\", value: true) // count all objects with given attribute name and value\n\nlet attributes = ...\nNSManagedObject.count(with: attributes) // count all objects with given attributes\n```\n\n#### Distinct\n```swift\ndo {\n    try NSManagedObject.distinctValues(for: \"city\") // get array of all distinct values for given attribute name\n} catch {\n    print(error)\n}\n\ndo {\n    let attributes = [\"country\", \"city\"]\n    try NSManagedObject.distinctRecords(for: attributes) // get dictionary with name and values of all distinct records for multiple given attributes\n} catch {\n    print(error)\n}\n```\n\n#### Auto Increment\nIf you need to have auto incremented attribute, just create one with Int type and get next ID like this:\n\n```swift\nNSManagedObject.autoIncrementedInteger(for: \"myCustomAutoID\") // returns next ID for given attribute of Integer type\n```\n\n#### Turn managed object into fault\n`NSFetchedResultsController` is designed to watch only one entity at a time, but when there is a bit more complex UI (ex. showing data from related entities too),\nyou sometimes have to manually refresh this related data, which can be done by turning 'watched' entity object into fault.\nThis is shortcut for doing just that (`mergeChanges` parameter defaults to `true`). You can read more about turning objects into faults in Core Data documentation.\n\n```swift\nlet managedObject = ...\nmanagedObject.refresh() // turns instance of managed object into fault\n```\n\n#### Batch update\nBatch updating is the 'new' feature from iOS 8. It's doing stuff directly in persistent store, so be carefull with this and read the docs first. Btw, `NSPredicate` is also optional parameter here.\n\n```swift\nNSManagedObject.batchUpdate(properties: [\"timeStamp\" : NSDate()]) // returns NSBatchUpdateResult?\n\nNSManagedObject.objectsCountForBatchUpdate(properties: [\"timeStamp\" : NSDate()]) // returns count of updated objects\n\nNSManagedObject.batchUpdateAndRefreshObjects(properties: [\"timeStamp\" : NSDate()]) // turns updated objects into faults after updating them in persistent store\n```\n\n## Installation\n\n- [Swift Package Manager](https://swift.org/package-manager/):\n\n    ```\n    .Package(url: \"https://github.com/tadija/AERecord.git\", majorVersion: 4)\n    ```\n    \n- [Carthage](https://github.com/Carthage/Carthage):\n\n    ```ogdl\n    github \"tadija/AERecord\"\n    ```\n\n- [CocoaPods](http://cocoapods.org/):\n\n    ```ruby\n    pod 'AERecord'\n    ```\n\n## License\nAERecord is released under the MIT license. See [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftadija%2FAERecord","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftadija%2FAERecord","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftadija%2FAERecord/lists"}