The Big Nerd Ranch Core Data Stack

Overview

BNR Core Data Stack

Carthage compatible CocoaPods Compatible GitHub license Build Status

Big Nerd Ranch

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 controller and delegate

Our FetchedResultsController<ManagedObjectType> sends Swifty delegate messages, rather than a mess of optionals.

Turn this:

func controller(
    _ controller: NSFetchedResultsController<NSFetchRequestResult>,
    didChange anObject: Any,
    at indexPath: IndexPath?,
    for type: NSFetchedResultsChangeType,
    newIndexPath: IndexPath?
) {
    guard let book = anObject as? Book else {
        preconditionFailure("Why is this thing an Any anyway? WTH!")
    }

    switch type {
    case .insert:
        guard let newIndexPath = newIndexPath else {
            preconditionFailure("Insertion to nowheresville? WHY IS THIS OPTIONAL?")
        }

        print("We have a new book! \(book.title)")
        tableView?.insertRows(at: [newIndexPath], with: .automatic)

    case .delete:
        guard let indexPath = indexPath else {
            preconditionFailure("Deletion you say? Where? WHY IS THIS OPTIONAL?")
        }

        tableView?.deleteRows(at: [indexPath], with: .automatic)

    case .move:
        guard let newIndexPath = newIndexPath else {
            preconditionFailure("It moved to NOWHERE! WHY IS THIS OPTIONAL?")
        }
        guard let indexPath = indexPath else {
            preconditionFailure("It moved from NOWHERE?! WHY IS THIS OPTIONAL!")
        }

        tableView?.moveRow(at: indexPath, to: newIndexPath)

    case .update:
        guard let indexPath = indexPath else {
            preconditionFailure("I give up! Remind me, why are we using Swift, again?")
        }

        tableView?.reloadRows(at: [indexPath!], with: .automatic)
    }
}

Into this:

func fetchedResultsController(
    _ controller: FetchedResultsController<Book>,
    didChangeObject change: FetchedResultsObjectChange<Book>
) {
    switch change {
    case let .insert(book, indexPath):
        print("Hey look, it's not an Any! A new book: \(book.title)")
        tableView?.insertRows(at: [indexPath], with: .automatic)

    case let .delete(_ /*book*/, indexPath):
        print("A deletion, and it has a from-where? Finally!")
        tableView?.deleteRows(at: [indexPath], with: .automatic)

    case let .move(_ /*book*/, fromIndexPath, toIndexPath):
        print("Whoah, wait, I actually HAVE index paths? Both of them? Yay!")
        tableView?.moveRow(at: fromIndexPath, to: toIndexPath)

    case let .update(_ /*book*/, indexPath):
        print("It's almost like I'm actually using Swift and not Obj-C!")
        tableView?.reloadRows(at: [indexPath], with: .automatic)
    }
}

It also has properly typed sections and subscripting operators. Because, we are writing Swift, are we not?

As a further bonus, you get our workarounds for some misbehavior of Core Data that contradicts the documentation, like this one:

// Work around a bug in Xcode 7.0 and 7.1 when running on iOS 8 - updated objects
// sometimes result in both an Update *and* an Insert call to didChangeObject,
// … (explanation continues) …

Convenient store change listening

Our EntityMonitor<ManagedObjectType> makes it easy to listen to all changes for a given ManagedObjectType:

/* EXAMPLE: NOTIFYING WHEN A MOC SAVES AUTHOR CHANGES */
let authorMonitor = EntityMonitor<Author>(context: moc, entity: authorEntityDescription, frequency: .onSave)
let authorMonitorDelegate = AuthorMonitorDelegate()
authorMonitor.setDelegate(authorMonitorDelegate)


/* EXAMPLE: AUTHOR MONITOR DELEGATE */
class AuthorMonitorDelegate: EntityMonitorDelegate {
    func entityMonitorObservedInserts(
        _ monitor: EntityMonitor<Author>,
        entities: Set<Author>
    ) {
        print("inserted authors:", entities)
    }

    func entityMonitorObservedModifications(
        _ monitor: EntityMonitor<Author>,
        entities: Set<Author>
    ) {
        print("modified authors:", entities)
    }

    func entityMonitorObservedDeletions(
        _ monitor: EntityMonitor<Author>,
        entities: Set<Author>
    ) {
        print("deleted authors:", entities)
    }
}

A friendlier managed object context

Extension methods on ManagedObjectContext ensure saves happen on the right queue and make your life easier:

// Gotta catch 'em all
let allBooks = try Book.allInContext(moc)

// Or at least one of 'em
let anyBook = try Book.findFirstInContext(moc)

// Ah, forget it. Rocks fall, everyone dies.
try Book.removeAllInContext(moc)


// Blocking save, including up through parent contexts,
// on the appropriate queue.
try moc.saveContextToStoreAndWait()

Interested?

Check out the documentation!

For more details on the design methodology, read "Introducing the Big Nerd Ranch Core Data Stack."

Why "Stack"? Previously, the Core Data Stack provided a full, ready-made Core Data stack. Apple now provide that themselves in NSPersistentContainer, so we're free to focus on the other benefits listed above, and we have [deprecated][#sec:deprecations] our own stack in favor of Apple's.

Swift-Only: Note that the Core Data Stack is intended to be used from Swift. Any use you can make of it from Objective-C is by luck, not design.

Support

Big Nerd Ranch can help you develop your app, or train you or your team in Swift, iOS, and more. We share what we learn here on GitHub and in bookstores near you.

For questions specific to the Core Data Stack, please open an issue.

Minimum Requirements

Running

Apps using BNR Core Data Stack can be used on devices running these versions or later:

  • macOS 10.10
  • tvOS 9.0
  • iOS 8.0

Building

To build an app using BNR Core Data Stack, you'll need:

  • Xcode 8.0
  • Swift 3.0

Usage

Type Safe Monitors

Fetched Results Controller

FetchedResultsController<T> is a type safe wrapper around NSFetchedResultsController using Swift generics.

Example

See BooksTableViewController.swift for an example.

Entity Monitor

EntityMonitor<T> is a class for monitoring inserts, deletes, and updates of a specific NSManagedObject subclass within an NSManagedObjectContext.

Example

See EntityMonitorTests.swift for an example.

NSManagedObject Extensions

Adds convenience methods on NSManagedObject` subclasses. These methods make fetching, inserting, deleting, and change management easier.

Example

let allBooks = try Book.allInContext(moc)
let anyBook = try Book.findFirstInContext(moc)
try Book.removeAllInContext(moc)

Installation

Installing with Carthage

Add the following to your Cartfile:

github "BigNerdRanch/CoreDataStack"

Then run carthage update.

In your code, import the framework as CoreDataStack.

Follow the current instructions in Carthage's README for up to date installation instructions.

Installing with CocoaPods

Add the following to your Podfile:

pod 'BNRCoreDataStack'

You will also need to make sure you're opting into using frameworks:

use_frameworks!

Then run pod install.

In your code, import the framework as BNRCoreDataStack.

Contributing

Please see our guide to contributing to the CoreDataStack.

Debugging Tips

To validate that you are honoring all of the threading rules it's common to add the following to a project scheme under Run > Arguments > Arguments Passed On Launch.

-com.apple.CoreData.ConcurrencyDebug 1

This will throw an exception if you happen to break a threading rule. For more on setting up Launch Arguments check out this article by NSHipster.

Excluding sensitive data from iCloud and iTunes backups

The default store location will be backed up. If you're storing sensitive information such as health records, and perhaps if you're storing any personally identifiable information, you should exclude the store from backup by flagging the URL on disk:

/* EXAMPLE: EXCLUDING A FILE FROM BACKUP */
var excludeFromBackup = URLResourceValues()
excludeFromBackup.isExcludedFromBackup = true

let someParentDirectoryURL: URL = 
var storeFileURL = URL(
    string: "MyModel.sqlite",
    relativeTo: someParentDirectoryURL)!
try! storeFileURL.setResourceValues(excludeFromBackup)

You then need to point your persistent container at that location:

/* EXAMPLE: AIMING YOUR CONTAINER AT A SPECIFIC URL */
// Ensure parent directory exists
try! FileManager.default.createDirectory(
    at: storeFileURL.deletingLastPathComponent(),
    withIntermediateDirectories: true)

// Configure the persistent container to use the specific URL
container.persistentStoreDescriptions = [
    NSPersistentStoreDescription(url: storeFileURL),
    ]

Prior to NSPersistentContainer, this would be done with Core Data Stack by:

/* EXAMPLE: DEPRECATED CORE DATA STACK WITH STORE URL */
CoreDataStack.constructSQLiteStack(
    withModelName: "MyModel",
    withStoreURL: storeFileURL) { result in
        switch result {
        case .success(let stack):
            // Use your new stack

        case .failure(let error):
            //handle error ...
        }
    }

Deprecations

iOS 10.0 / macOS 10.12

  • Deprecated: The CoreDataStack class itself.
    • Replacement: Use Apple's NSPersistentContainer instead. The [Container Example](./Container Example/README.md) demonstrates how to use NSPersistentContainer with the BNR Core Data Stack.
  • Deprecated: The CoreDataModelable protocol.
    • Replacement: Use the type method NSManagedObject.entity(). Many of the convenience methods formerly available on CoreDataModelable are now offered by BNR Core Data Stack as extension methods on NSManagedObject as FetchHelpers.
Comments
  • Make stack type enum take an optional NSURL

    Make stack type enum take an optional NSURL

    @lyricsboy I chatted with @jgallagher about this idea of throwing and returning error types in a result and he suggested I make the NSURL a part of the StackType enum itself.

    I opted for an implicitly unwrapped optional so that a default URL can still be filled in if you don't want to specify a desired URL. This also allows the construct method's stack type parameter to also be optional.

    I stubbed in todo statements for the two methods that were assuming SQLIte store types. If you like this solution I'll go back and handle those cases.

    opened by rcedwards 13
  • Crash saving background context

    Crash saving background context

    Any idea on where's the issue in this crash?

    Thread : Crashed: NSManagedObjectContext 0x15462eaa0: Background Worker Context
    0  libswiftCore.dylib             4317556504 usesNativeSwiftReferenceCounting_unowned(void const*) + 156
    1  libswiftCore.dylib             4317557536 swift_unknownWeakRelease + 36
    2  BNRCoreDataStack               4305106224 _TFFE16BNRCoreDataStackCSo22NSManagedObjectContext11saveContextFS0_FTGSqFOS_13SuccessResultT___T_U_FGSqFS1_T__T_ + 268
    3  CoreData                       6501320960 developerSubmittedBlockToNSManagedObjectContextPerform + 196
    4  libdispatch.dylib              6860510888 _dispatch_client_callout + 16
    5  libdispatch.dylib              6860560108 _dispatch_queue_drain + 864
    6  libdispatch.dylib              6860525996 _dispatch_queue_invoke + 464
    7  libdispatch.dylib              6860510888 _dispatch_client_callout + 16
    8  libdispatch.dylib              6860569408 _dispatch_root_queue_drain + 2140
    9  libdispatch.dylib              6860567260 _dispatch_worker_thread3 + 112
    

    I can't find what called save context. It's a fabric remote crash report.

    opened by bitomule 9
  • Swift 2.0

    Swift 2.0

    Addresses issues #7 and #11 by opting to create a single nested MOC style stack with a method for creating a separate MOC with its own persistent store coordinator for handling batch type operations. Considerations will be documented in the README with the stack type diagrams and some examples in the sample project. #9 was fixed by removing that unnecessary class.

    @jgallagher, @zwaldowski, @lyricsboy, @randomstep if any of you have time please take a look at this PR as a good time for an overall code review of the project since it hasn't had many additional eyes on it. Thanks

    opened by rcedwards 8
  • Question for BatchUpdateRequest.

    Question for BatchUpdateRequest.

    Question

    Hi, I really enjoy using this framework, but I have something unclear about batch update.

    The test project goes here. CoreDataTest.zip

    I have created CoreDataStack in ViewController.swift and seed initial data like this.

    private func seedInitData(stack:CoreDataStack){
            let moc = stack.newChildContext()
            do {
                try moc.performAndWaitOrThrow {
                    let books = ["Book 1", "Book 2", "Book3"]
                    for bookTitle in books {
                        let book = Book(managedObjectContext: moc)
                        book.title = bookTitle
                        book.isRent = false
                    }
                    try moc.saveContextAndWait()
                }
            } catch {
                print("Error creating initial data: \(error)")
            }
        }
    

    After that did some testing on testStack() function in NewViewController.swift file.

    func testStack(){
            let context = stack.newChildContext(concurrencyType: .PrivateQueueConcurrencyType, name: "batchWorker")
            let batchRequest = NSBatchUpdateRequest(entityName: "Book")
            batchRequest.propertiesToUpdate = ["isRent" : true]
            batchRequest.resultType = .UpdatedObjectIDsResultType
            do{
    
                // First, try to fetch all book object from core data.
                let objs = try context.executeFetchRequest(NSFetchRequest(entityName: "Book"))
                print("--------------Book objects before performing batch updates-----------")
                objs.forEach{
                    let book = $0 as! Book
                    // It should show false
                    print("title : \(book.title), Rent = \(book.isRent)")
                }
                let batchResult = try context.executeRequest(batchRequest) as! NSBatchUpdateResult
                let objectIDS = batchResult.result as! [NSManagedObjectID]
    
                print("\n\n--------------After performing batch request & refreshObject-----------")
                objectIDS.forEach{
                    let object = context.objectWithID($0) as! Book
                    context.refreshObject(object, mergeChanges: false)
    
                    // I think this should show true, but showing false now (So not changed)
                    print("title : \(object.title), isRent : \(object.isRent)")
                }
            }catch{}
        }
    

    Output Log

    --------------Book objects before performing batch updates-----------
    title : Optional("Book 2"), Rent = Optional(0)
    title : Optional("Book 1"), Rent = Optional(0)
    title : Optional("Book3"), Rent = Optional(0)
    
    
    --------------After performing batch request & refreshObject-----------
    title : Optional("Book 2"), isRent : Optional(0)
    title : Optional("Book 1"), isRent : Optional(0)
    title : Optional("Book3"), isRent : Optional(0)
    

    I think after batch request is performed, it should show true. But it's showing false. Is this right behaviour or did I understand wrong?

    It will be appreciated if anyone can help me.

    question 
    opened by alexchan1680 7
  • Remove unneeded properties

    Remove unneeded properties

    Summary of Changes

    • managedObjectModel is now a stored property which makes storing bundle and modelName unnecessary
    • private init(modelName: String, bundle: Bundle, persistentStoreCoordinator: NSPersistentStoreCoordinator, storeType: StoreType) becomes a convenience initalizer
    • private init(model: NSManagedObjectModel, persistentStoreCoordinator: NSPersistentStoreCoordinator, storeType: StoreType) becomes the default initializer
    opened by HSchultjan 6
  • When using Mogenerator, making a ManagedObject implement CoreDataModelable gives error

    When using Mogenerator, making a ManagedObject implement CoreDataModelable gives error

    Feature Request

    What would you like to see that is not available?

    I have created my Model Objects with MoGenerator. When I make one of those generated classes implement CoreDataModelable, I get an error: /Model/Custom/Region.swift:7:20: Getter for 'entityName' with Objective-C selector 'entityName' conflicts with method 'entityName()' from superclass '_Region' with the same Objective-C selector

    Question

    Would it be a better idea to put all those very usefull functions in a straightforward: extension NSManagedObject { }

    Expected behavior

    Either way, I would like to be able to use the useful functions you implemented in CoreDataModelable.

    Actual behavior

    Compile error: Getter for 'entityName' with Objective-C selector 'entityName' conflicts with method 'entityName()' from superclass '_Region' with the same Objective-C selector

    Additional Context

    Xcode 7.3.1, Mogenerator 1.29, BNRCoreDataStack 1.2.5, Swift 2.2.

    Thanks for contributing to the CoreDataStack!

    question 
    opened by Yourney 6
  • Use dedicated Stack background queue, rather than global queues

    Use dedicated Stack background queue, rather than global queues

    Summary of Changes

    We may be experiencing issues with starvation of global queues, since in our particular use case we spawn rather a lot of batch contexts. Please see example stack trace attach to reply. We appear to have a lot of threads stuck in -[NSPersistentStoreCoordinator addPersistentStoreWithType:configuration:URL:options:error:].

    It seems reasonable enough to just serialise stack creation, which is not possible using a global queue. So, simply add a serial queue property and make the necessary interface changes. I left the global queue and the default argument as well.

    Please let me know what you think.

    question 
    opened by itsthejb 6
  • Why not return to the main thread after constructing a stack ?

    Why not return to the main thread after constructing a stack ?

    It is pretty common inside a TableViewController's init or viewDidLoad method to have initialisation code like the following:

    override func viewDidLoad() {
      super.viewDidLoad()
      CoreDataStack.constructSQLiteStack(withModelName: "SomeName") { outcome in
        print(NSThread.isMainThread())     // false
        switch outcome {
          case .Failure(let error)        : print(error)
          case .Success(let coreDataStack):
            self.coreDataStack = coreDataStack
            self.tableView.reloadData()    // crash
        }
      }  
    }
    

    This code will crash however because the callback is executed on a background thread (created by setupSQLiteBackedCoordinator.

    Unless I missed something, it seems to me it would be less confusing if the callback was executed on the main thread. After all, once the stack has been set up why remain in the background thread?

    A pretty simple fix would be to just wrap the callback calls inside constructSQLiteStack:

        dispatch_async(dispatch_get_main_queue(), { 
          callback(.Success(stack))  // or callback(.Failure(error))
        })
    
    enhancement upcoming release 
    opened by plm75 6
  • Use withoutActuallyEscaping for helpers on Swift 3.1

    Use withoutActuallyEscaping for helpers on Swift 3.1

    Starting in Swift 3.1, the optimizer is free to introduce incorrect optimizations for the former implementation.

    Before:

    public func performAndWaitOrThrow<Return>(_ body: () throws -> Return) rethrows -> Return {
            func impl(execute work: () throws -> Return, recover: (Error) throws -> Void) rethrows -> Return {
                var result: Return!
                var error: Error?
    
                // performAndWait is marked @escaping as of iOS 10.0.
                // swiftlint:disable type_name
                typealias Fn = (() -> Void) -> Void
                let performAndWaitNoescape = unsafeBitCast(self.performAndWait, to: Fn.self)
                performAndWaitNoescape {
                    do {
                        result = try work()
                    } catch let e {
                        error = e
                    }
                }
    
                if let error = error {
                    try recover(error)
                }
    
                return result
            }
    
            return try impl(execute: body, recover: { throw $0 })
        }
    

    After:

     public func performAndWaitOrThrow<Return>(_ body: () throws -> Return) rethrows -> Return {
            return try withoutActuallyEscaping(body) { (work) in
                var result: Return!
                var error: Error?
    
                performAndWait {
                    do {
                        result = try work()
                    } catch let e {
                        error = e
                    }
                }
    
                if let error = error {
                    throw error
                } else {
                    return result
                }
            }
        }
    
    opened by zwaldowski 5
  • Entity name check should not fail because of module name

    Entity name check should not fail because of module name

    Feature Request

    Make sure the entity name comparison in EntityMonitor does not fail as a result of the module name. Utilize NSClassFromString to get a string for comparison.

    Expected behavior

    Entity matching class should not fail based on module name when creating an EntityMonitor

    Actual behavior

    It fails the match and creates a precondition failure.

    bug upcoming release 
    opened by rcedwards 5
  • Linker issue

    Linker issue

    Sorry my previous issue was very thin in information.

    I've managed to reproduce the issue in the attached project. I'm not sure if the way I used the init method is still valid. The method is marked deprecated for iOS10 but the project I'm on is targeting iOS9. And I get no build errors so it should be fine?

    So I might missed something when migrating to the new version? I moved from swift 2 to swift 3. And from CoreDataStack 1.2.5 to 2.0.2.

    BNRTest.zip

    question 
    opened by mikaelbartlett 5
Releases(v2.3.1)
  • v2.3.1(Oct 17, 2017)

  • v2.2.1(May 17, 2017)

  • v2.2.0(Mar 29, 2017)

  • v2.1.0(Jan 17, 2017)

    • Introduces the ability to add custom Store Options to your NSPersistentStoreCoordinator #185. Thanks to @Aranoledur
    • Fixes potential false positive assertions for class name in EntityMonitor Issue: #180 PR: #184
    Source code(tar.gz)
    Source code(zip)
  • v1.4.0(Jan 17, 2017)

    • Introduces the ability to add custom Store Options to your NSPersistentStoreCoordinator #177. Thanks to @Aranoledur
    • Fixes potential false positive assertions for class name in EntityMonitor Issue: #180 PR: #183
    • This will be the final release supporting Swift 2.3. Further bug fixes and features will only be added to Swift 3.0 (master branch).
    Source code(tar.gz)
    Source code(zip)
  • v2.0.2(Oct 25, 2016)

    • Change access level to public for func performAndWaitOrThrow NSPersistentStoreCoordinator and NSManagedObjectContext extensions.

    Addresses:

    #172

    Source code(tar.gz)
    Source code(zip)
  • v2.0.1(Oct 14, 2016)

    • Resolves some target membership and @available designations for tvOS target #167
    • Above issue was preventing publishing 2.0.0 to CocoaPods

    Addresses:

    #166

    Source code(tar.gz)
    Source code(zip)
  • v2.0.0(Oct 12, 2016)

    • Updated syntax for Swift 2.3 and Xcode 8.0
    • Deprecates CoreDataStack class
    • Deprecates CoreDataModelable and migrates utility functions to and extension of NSManagedObject
    • Creates a new sample project showing off NSPersistentContainer usage
    • Splits unit test cases into either a Deprecated target (testing those classes that have been deprecated) or a Non-Deprecated target (testing those classes that will not be deprecated).
    • ModifiesperformAndWaitOrThrow to make use of rethrows and @noescape

    All above changes in PR #160 Addresses: #152 #162

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0(Oct 11, 2016)

    • Updated syntax for Swift 2.3 and Xcode 8.0
    • Deprecates CoreDataStack class
    • Deprecates CoreDataModelable and migrates utility functions to and extension of NSManagedObject
    • Creates a new sample project showing off NSPersistentContainer usage
    • Splits unit test cases into either a Deprecated target (testing those classes that have been deprecated) or a Non-Deprecated target (testing those classes that will not be deprecated).

    All above changes in PR #159 Addresses: #152

    Source code(tar.gz)
    Source code(zip)
  • v1.2.6(Jun 24, 2016)

  • v1.2.5(Jun 1, 2016)

    • Adds a convenience save function that will persist changes up the chain to the NSPersistentStore #138
    • Handles another error in Apple's NSFetchedResultsController callbacks #137
    • Tweaks to CI and documentation generation
    Source code(tar.gz)
    Source code(zip)
  • v1.2.4(Apr 26, 2016)

    • constructSQLiteStack, newBatchOperationContext, and resetStore now all take an optional GCD queue to call back on. #129
    • newBackgroundWorkerMOC has been deprecated in favor of newChildContext which allows you to create MOCs of different NSManagedObjectContextConcurrencyTypes #130
    • Jazzy docs formatting updates
    Source code(tar.gz)
    Source code(zip)
  • v1.2.3(Apr 20, 2016)

  • v1.2.2(Apr 8, 2016)

    • Ensures only app extension safe APIs are used #117 thanks to @nadavhart
    • Adds countInContext to CoreDataModelable #118 thanks to @darrarski
    Source code(tar.gz)
    Source code(zip)
  • v1.2.1(Mar 23, 2016)

  • v1.2.0(Mar 11, 2016)

    • Support for Mac OS X :tada: #104
    • Fastlane for running tests locally and on travis ci #106
    • Contribution Guidelines #102
    • Additional API to CoreDataModelable #99 and FetchedResultsController #98
    Source code(tar.gz)
    Source code(zip)
  • v1.1.5(Feb 29, 2016)

    • File location changes to support Swift Package Manager #94
    • Open up a couple convenience methods in CoreDataModelable #91
    • Added some more usage examples to the sample project #92 #87
    Source code(tar.gz)
    Source code(zip)
  • v1.1.4(Feb 3, 2016)

  • v1.1.3(Feb 2, 2016)

    • Enabled testability for all targets (This will resolve an issue some have seen when installing via carthage) https://github.com/bignerdranch/CoreDataStack/commit/4aac4cd60ab6f0871fac5bb12ce11da94f71aeec
    • Added a carthage checkout test to ensure each release is installable
    • Various CI and Doc improvements
    Source code(tar.gz)
    Source code(zip)
  • v1.1.2(Jan 14, 2016)

  • v1.1.1(Dec 30, 2015)

    • Added support for tvOS #68
    • Fixed a bug that would cause the main queue context from not persisting its changes along to the persistent store after you've performed a reset on the stack. #72 thanks to @jimabc
    • Expanded and improved our unit testing #70 (also dropped all ObjC #67 pure Swift!)
    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Dec 4, 2015)

    • Introduces a type (EntityMonitor) for performing custom monitoring of changes to a managed object context. (#52)
      • Adds a protocol (CoreDataModelable) for bringing extra features to NSManagedObject through protocol extensions. (#52)
        • init(managedObjectContext:) convenience
        • findFirst, allInContext, removeAll and other fetch conveniences
    • Introduces a type-safe, mostly drop-in equivalent to NSFetchedResultsController (FetchedResultsController<T>). (#55)
    • Adds rethrowing performBlockAndWait to NSManagedObjectContext and NSPersistentStoreCoordinator. (#59)
    • Minor performance and stability improvements.
    Source code(tar.gz)
    Source code(zip)
  • v1.0.2(Nov 13, 2015)

    • Fixed rare crash with weak capture of self in MOC save flow
    • Moved custom result types within the CoreDataStack scope to prevent collision in other projects
    Source code(tar.gz)
    Source code(zip)
  • v1.0.1(Nov 6, 2015)

  • v1.0.0(Oct 19, 2015)

  • v0.3.1(Sep 21, 2015)

  • v0.3.0(Aug 27, 2015)

    Swift 2.0 compatible!

    Simplified interface for constructing either a SQLite-backed or in-memory version of CoreDataStack.

    Now only supports parent/child private queue context setup.

    Improved test coverage.

    Source code(tar.gz)
    Source code(zip)
  • v0.3.0b2(Aug 23, 2015)

  • v0.2.0(May 15, 2015)

    • Stack initialization is now asynchronous with a callback for SQLite stores
    • Stacks can now be initialized with an in memory backing store
    • SQLite Journal Mode is WAL now except for app runs that require a migration
    • More naming changes
    Source code(tar.gz)
    Source code(zip)
  • v0.1.0(May 6, 2015)

    • ThreadConfinementStack renamed to SharedStoreMOCStack
    • Background Contexts are removed from Notification Center on deinit
    • NSConfinementConcurrencyType use was replaced with NSPrivateQueueConcurrencyType and NSMainQueueConcurrencyType
    • Save errors are accessible to callers of extension
    Source code(tar.gz)
    Source code(zip)
Owner
Big Nerd Ranch
Big Nerd Ranch
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
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
DataKernel is a minimalistic wrapper around CoreData stack to ease persistence operations.

DataKernel What is DataKernel? DataKernel is a minimalistic wrapper around CoreData stack to ease persistence operations. It is heavily inspired by Su

Denis 16 Jun 2, 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
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
A feature-light wrapper around Core Data that simplifies common database operations.

Introduction Core Data Dandy is a feature-light wrapper around Core Data that simplifies common database operations. Feature summary Initializes and m

Fuzz Productions 33 May 11, 2022
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
This project server as a demo for anyone who wishes to learn Core Data in Swift.

CoreDataDemo This project server as a demo for anyone who wishes to learn Core Data in Swift. The purpose of this project is to help someone new to Co

null 1 May 3, 2022