Skip to content

PeakCoreData is a Swift microframework providing enhancements and conveniences to Core Data.

License

Notifications You must be signed in to change notification settings

3Squared/PeakCoreData

Repository files navigation

PeakCoreData

PeakCoreData is a Swift microframework providing enhancements and conveniences to Core Data. It is part of the Peak Framework.

Observers

ManagedObjectObserver

The ManagedObjectObserver class can be used to observe changes made to a single managed object. State changes include when it is refreshed, updated or deleted.

var event: Event!
var eventObserver: ManagedObjectObserver<Event>!

override func viewDidLoad() {
    super.viewDidLoad()
    
    eventObserver = ManagedObjectObserver(managedObject: event)
    eventObserver.startObserving() { [weak self] obj, changeType in
        guard let strongSelf = self else { return }
        switch changeType {
        case .initialised, .refreshed, .updated:
            strongSelf.updateView()
        case .deleted:
            strongSelf.navigationController?.popToRootViewController(animated: true)
        }
    }
}

CountObserver

The CountObserver class can be used to observe changes to the number of NSManagedObject objects as defined by a generic type and an optional NSPredicate.

var countObserver: CountObserver<Event>!

override func viewDidLoad() {
    super.viewDidLoad()

    let predicate = NSPredicate(format: "%K == false", argumentArray: [#KeyPath(Event.isHidden)])
    countObserver = CountObserver<Event>(predicate: predicate, context: viewContext)
    countObserver.startObserving() { [weak self] count in
        guard let strongSelf = self else { return }
        strongSelf.countLabel.text = String(count)
    }
}

Fetched Data Sources

FetchedCollection

FetchedCollection is a wrapper for NSFetchedResultsController which acts as its own delegate and exposes changes though a closure.

let fetchedCollection = FetchedCollection(fetchRequest: Event.sortedFetchRequest(), context: viewContext)

fetchedCollection.onChange = { collection, update in
    // use collection, or process updates
}

// subscriptable
let object = fetchedCollection[0, 0]

// or with a tuple
let object = fetchedCollection[(0, 0)]

// or with an index path
let object = fetchedCollection[IndexPath(row: 0, section: 0)]

This allows you to decouple the NSFetchedResultsController from your viewcontroller.

FetchedCollectionViewDataSource and FetchedTableViewDataSource

These classes take care of the boiler-plate code needed to use a NSFetchedResultsController with a UITableView or UICollectionView.

class EventsTableViewController: UITableViewController {

    var dataSource: FetchedTableViewDataSource<EventsTableViewController>!

    override func viewDidLoad() {
        super.viewDidLoad()

        let frc = NSFetchedResultsController(
            fetchRequest: Event.sortedFetchRequest(), 
            managedObjectContext: viewContext, 
            sectionNameKeyPath: nil, 
            cacheName: nil
        )
        dataSource = FetchedTableViewDataSource(
            tableView: tableView, 
            cellIdentifier: EventTableViewCell.cellIdentifier, 
            fetchedResultsController: frc, 
            delegate: self
        )
        dataSource.animateUpdates = true
        dataSource.onDidChangeContent = {
            print("Something changed")
        }
        dataSource.performFetch()
    }
}

extension EventsTableViewController: FetchedTableViewDataSourceDelegate {
    
    func identifier(forCellAt indexPath: IndexPath) -> String {
        return EventTableViewCell.cellIdentifier
    }

    func configure(_ cell: EventTableViewCell, with object: Event) {
        cell.textLabel?.text = object.date?.description
    }
}

Operations

CoreDataOperation

CoreDataOperation is a concurrent Operation subclass that can be used to perform core data tasks on a background thread. To use, simply subclass CoreDataOperation then override the performWork(in:) method.

Things to note about this operation:

  • CoreDataOperation simply wraps the performBackgroundTask((NSManagedObjectContext) -> Void) method on NSPersistentContainer in a operation.
  • To finish the operation you must call saveAndFinish().
  • Changes will only be merged in to your viewContext if you have set the automaticallyMergesChangesFromParent on viewContext to true.
  • CoreDataOperation conforms to ProducesResult and so can be used to produce a Result.

CoreDataChangesetOperation

A CoreDataOperation subclass that returns a Changeset struct containing all the NSManagedObjectID objects that were inserted and updated during the operation.

CoreDataBatchImportOperation and CoreDataSingleImportOperation

Two CoreDataChangesetOperation subclasses that can be used to import an array of intermediate objects or a single intermediate object in to Core Data. They would normally be used to import Decodable objects from your web service. These operations work automatically as long as the following requirements are met:

  • The intermediate object must conform to ManagedObjectUpdatable and UniqueIdentifiable.
  • The NSManagedObject type you are converting to must conform to ManagedObjectType and UniqueIdentifiable.

Protocols

ManagedObjectType and UniqueIdentifiable

To give your NSManagedObject subclasses access to a range of helper methods for inserting, deleting, fetching and counting, simply make them conform to the ManagedObjectType and UniqueIdentifiable protocols. Doing so will also allow you to use CoreDataBatchImportOperation and CoreDataSingleImportOperation.

PersistentContainerSettable

Each view controller that needs access to the NSPersistentContainer should conform to PersistentContainerSettable. Conforming to this protocol gives you easy access to the viewContext property and a method for saving the viewContext. It also allows your NSPersistentContainer to be passed around more easily in prepare(for:sender:).

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let controller = segue.destination as? PersistentContainerSettable {
        controller.persistentContainer = persistentContainer
    }
    if let navController = segue.destination as? UINavigationController, let controller = navController.topViewController as? PersistentContainerSettable {
        controller.persistentContainer = persistentContainer
    }
}

Contributing

Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.

Versioning

We use SemVer for versioning.

License

This project is licensed under the MIT License - see the LICENSE.md file for details

Acknowledgments

Peak Framework

The Peak Framework is a collection of open-source microframeworks created by the team at 3Squared, named for the Peak District. It is made up of:

Name Description
PeakOperation Provides enhancement and conveniences to Operation, making use of the Result type.
PeakNetwork A networking framework built on top of Session using PeakOperation, leveraging the power of Codable.

About

PeakCoreData is a Swift microframework providing enhancements and conveniences to Core Data.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •  

Languages