bignerdranch / coredatastack Goto Github PK
View Code? Open in Web Editor NEWThe Big Nerd Ranch Core Data Stack
License: MIT License
The Big Nerd Ranch Core Data Stack
License: MIT License
Hi again! Want to say that I really like this framework and want to continue to use it without copying source files. But right now I need a way to add some options to persistent store. I need to encrypt my core data using FileProtection: Complete. Or even better: init CoreDataStack with custom NSPersistentStoreCoordinator. I can do it and create Pull request. But do you need this feature in this framework (will you accept PR)? Or maybe this feature has already been implemented and I couldn't find a way to use it?
newBatchOperationContext
I am trying to build with Xcode 8 beta 3, while keep using Swift 2.3, and I get a few build errors. Can you fix them, so that I can get the fixes through 'pod install'?
There are issues in CoreDataStack.swift and in CoreDataModelable.swift.
Build errors in CoreDataStack.swift:
let _ = try? fm.removeItemAtURL(storeURL.URLByAppendingPathComponent("-shm"))
(!)Value of optional type 'NSURL?' not unwrapped; did you mean to use '!' or '?'?
let _ = try? fm.removeItemAtURL(storeURL.URLByAppendingPathComponent("-wal"))
(!)Value of optional type 'NSURL?' not unwrapped; did you mean to use '!' or '?'?
URLByAppendingPathComponent
returns an optional which should be unwrapped or handled correctly. Quick (but possibly unsafe) fix:
let _ = try? fm.removeItemAtURL(storeURL.URLByAppendingPathComponent("-shm")!)
let _ = try? fm.removeItemAtURL(storeURL.URLByAppendingPathComponent("-wal")!)
Build error in CoreDataModelable.swift:
var error: NSError? = nil
let count = context.countForFetchRequest(fetchReqeust, error: &error)
(!)Extra argument 'error' in call
if let error = error { throw error }
guard count != NSNotFound else { return 0 }
return count
That should probably look something like this:
var count: Int = NSNotFound
do {
count = try context.countForFetchRequest(fetchReqeust)
}
catch let error {
throw error
}
guard count != NSNotFound else { return 0 }
return count
Thank you and cheers!
Peter
Sorry to bother you guys again. I am having an issue using the NSBatchDeleteRequest object with the CoreDataStack and the FetchedResultsController.
The issue seems to be that the FetchedResultsController doesn't receive the delegate callbacks after the delete occurs? So none of the UI gets updated removing the items on the screen. I am initializing CoreDataStack with CoreDataStack.constructSQLiteStack so I can see that the database changes are occurring in the table and also you can see in the code below I am printing out how many items are affected.
Below is an example of what I am testing against on the BooksTableViewController. Is there a way to use the NSBatchDeleteRequest to deal with Bulk Deletes or do you have to fetch the items and then delete them 1 at a time with Context.deleteObject(object)?
let deleteItems = [
"American Pastoral",
"An American Tragedy",
"Animal Farm"
]
let request = NSFetchRequest(entityName: Book.entityName)
request.predicate = NSPredicate(format: "title IN %@", deleteItems)
let del = NSBatchDeleteRequest(fetchRequest:request)
del.resultType = .ResultTypeCount
do{
if let moc = coreDataStack.newBackgroundWorkerMOC(), let batchResult = try moc.executeRequest(del) as? NSBatchDeleteResult{
if let count = batchResult.result as? Int where count > 0 {
print("delete result:\(count)")
try moc.saveContextAndWait()
}
}
}catch{
print(error)
}
We should look into how we can separate construction of the CoreDataStack from using an instance.
A single concrete class with factory-ish methods is difficult to mock in tests. Ideally the instance methods could be in a protocol.
I don't know that it will make the contract easy to satisfy with valid objects (NSManagedObjectContext in particular requires the stack in some form), but it is probably the right design choice.
Idea here is that the context type here: https://github.com/bignerdranch/sms-ios-mac-data-storage/blob/master/projects/CoreDataSMS/CoreDataSMS/CoreDataStack.swift#L135 can be NSMainQueueConcurrencyType
and the context type here https://github.com/bignerdranch/sms-ios-mac-data-storage/blob/master/projects/CoreDataSMS/CoreDataSMS/CoreDataStack.swift#L152 can be NSPrivateQueueConcurrencyType
This class will still follow the older pattern of not having parent/child context relationships but with this change there is no need to return a tuple of MOC/dispatch_queues and the contexts can take advantage of performBlock and performBlockAndWait calls.
Please, consider adding my Add On to list on wiki page. It adds convenience extension to NSManagedObjectContext
that that makes saving contexts easier and more efficient.
Description | Repository |
---|---|
NSManagedObjectContext convenience extension for saving or rolling back context and performing grouped saves. |
darrarski/BNRCoreDataStackConvenienceSaves |
Brief description is included in the README.md on Add On's repository. There are also tests that demonstrates example usage. Add On integration is handled by Cocoapods.
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{}
}
--------------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.
If I create a new FetchedResultsController with context a newBackgroundWorkerMOC then only fetchedResultsControllerDidPerformFetch is called from the delegate but the fetchedResultsControllerWillChangeContent, fetchedResultsControllerDidChangeContent, didChangeObject, etc are not called.
The newBackgroundWorkerMOC is stored in a member variable and the saves and updates of managed objects are taking place in this managed object context. Still, the fetched results controller delegate is not called.
For some reason I can't get the iOS 9 Core Data update for Unique Constraints to work in CoreDataStack? Is there a trick to this? I have seen articles saying to do this you need to change the policy to MergeByPropertyObjectTrumpMergePolicyType is this something that needs to be updated in the class?
Swift 3 allows forced conversion between @escaping
functions and not. You can then use what DispatchQueue.sync(execute:)
does to allow sync
to return and/or rethrow values:
extension NSManagedObjectContext {
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.
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 })
}
}
Used like:
let value: Int = try context.performAndWaitOrThrow {
throw SomeError()
}
I would like to have the option to create child contexts in the main queue.
It would be great if you could create a new child context in the main queue that can be used for example when the user needs to update and NSManagedObject. That way if the user decides not to save the changes, you can just get rid of the context and everything will be as before the changes.
Hello, i writed the project using your CoreDataStack, and when i add some entities to DB and then save (mainQueueContext.save) only entities count is saved but not their attributes. Here is the project for see: https://github.com/andertsk/PersonalContacts (List tab)
Achieve process parity of Travis CI with Circle CI.
We should continue to be able to publish docs, verify carthage/cocoa pod install, run unit tests etc.
n/a
Experiencing extremely long build times and as of the last couple days unable to get a completed build in general from Travis CI.
We should look into a way to reset the persistent store for an in-memory stack in an equivalent way.
The name of this function can also be changed to just resetStore
or something to avoid the SQLite-specifics.
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.
Are there any blobs of code we frequently rewrite as part of testing something that relies on Core Data? If so, could we make those available for use in tests alongside the useful methods available for getting Core Data set up in the main app?
Maybe this will work with TVOS as it is, but the cocoa pods spec currently just says os x
See #71
Article: http://benedictcohen.co.uk/blog/archives/308
Mentioned:
-awakeFromInsert
breaking doc contract and being called multiple times as changes propagate upwardsI'm specifically curious about contrasting the recommendation to have main queue -> PSC with private queue worker contexts hooked up to main queue context only as needed, vs the main -> private -> PSC stack recommended in this repo. What are the dis/advantages and tradeoffs between the two?
The NSManageObjectContext
s themselves are not being added as an observer to any notification so this is no longer necessary.
The repository should have a CHANGELOG.MD
This should be easy to run and documented in the WIKI under Releases
No changelog in place
This has a lot of potential skywinder/github-changelog-generator
I'm using resetSQLiteStore method but when I run any context save after that it crashes saying that there's no persistent coordinator present. Calling resetSQLiteStore and then creating a new stack fixes the problem.
Any ideas?
7779eac added the EntityMonitor and some utils within the protocol CoreDataModelable, it would be helpful if this was added to the README and the sample project.
As advised in #119 I have created Add On that includes my extensions for convenience managed object updates. Please, include it on Add Ons wiki page.
Name | Repository |
---|---|
BNRCoreDataStackConvenienceUpdates | darrarski/BNRCoreDataStackConvenienceUpdates |
Brief description is included in the README.md on Add On's repository. There are also tests that demonstrates example usage. Add On integration is handled by Cocoapods.
waiting on facebookarchive/xctool#528
I'm using a batchOperationContext to import a big data set. It works but I don't know why objects from one entity are saved on disk but not on memory. I'm trying to re-fetch from disk but can't make it work.
Right now the only thing that works is creating a new batchOperationContext and fetching the entity there but this seems to be overkill.
Any ideas? How are changes from batchOperationContext merged into main context? Any way to reset main context and re-fetch from disk?
If I embed the CoreDataStack source files directly in my project, I can use CoreDataModelable entityInContext (since it will be defined as internal). But if I embed CoreDataModelable as a framework, entityInContext is not available, since only public functions are available in a framework.
"Require Only App-Extension-Safe API" build setting is set to NO on all targets, which causes Xcode to show a warning - "Linking against a dylib which is not safe for use in application extensions", when CoreDataStack is used as a framework (via Carthage, for example).
Can constructSQLiteStack return an error / errorType in the CoreDataStackSetupCallback when the model file does not exist?
After profiling the performance trade offs of a nested managed object context stack and a shared persistent store stack (see #7 (comment)) I do not see the value of maintaining two separate stacks.
Instead the NestedContextStack will be the only stack maintained and part of this repo.
For long running batch imports there will be an API added to the nested context stack that will vend the user an NSManagedObjectContext with its very own persistent store coordinator that only shares the store file with the NestedContextStack. This is the recommend method from Apple for this type of import operation.
When I attempt to compile a project with the BNRCoreDataStack pod from the Swift 2.3 branch (Xcode 8), I receive an "undefined symbols for architecture [arm64]" linker error regarding the CoreDataModelable class initiation method. Any clues as to why this might be occurring?
Undefined symbols for architecture arm64: "(extension in BNRCoreDataStack):BNRCoreDataStack.CoreDataModelable<A where A: __ObjC.NSManagedObject, A: BNRCoreDataStack.CoreDataModelable>.init (managedObjectContext : __ObjC.NSManagedObjectContext) -> A", referenced from: Smartech.Battery.init (information : SmartechBluetooth.BatteryInformation, name : Swift.String, insertIntoManagedObjectContext : __ObjC.NSManagedObjectContext) -> Smartech.Battery in Battery.o ld: symbol(s) not found for architecture arm64
rather than being computed on each call, it could be private(set) and we redo the mappings at the end of performFetch. Or, alternatively, we make the property a lazy collection (example here) that does the mapping ad-hoc.
Documents directory is coupled into CoreDataStack and would need to be more flexible to support OS X.
Adopt Swift 3.0 toolchain, API naming, and syntax.
Add usage recommendations with regards to NSPersistentContainer
availability (iOS 10 macOS 10.12)
Provide Swift 2.3 branch as well
Currently the base class CoreDataStack
is built exclusively for SQLite persistent stores. By modifying its implementation to accept an in memory store testing can be much simpler when assuming a fresh store.
Related to testing patterns in #6
Creating a cocoapods library, that uses the pod BNRCoreDataStack. The project that I'm working on is an Objective-C project, the CoreDataStack library imports successfully and builds, but fails to install onto the Simulator (archiving and installing through iTunes works fine).
Note:
It only builds after making CoreDataStack inherit from NSObject and adding @objc(CoreDataStack)
before the class, also commenting out privateQueueContext.persistentStoreCoordinator = persistentStoreCoordinator
line in private init(modelName: String, bundle: NSBundle, persistentStoreCoordinator: NSPersistentStoreCoordinator, storeType: StoreType)
because Use of 'self' in property access 'privateQueueContext' before super.init initializes self
. Commented it out because I just wanted it to build first, ask questions later. Don't know Swift that well to fix this properly, maybe suggestions?
The build should install onto the simulator and run fine
I get the error The operation couldn't be completed. (LaunchServicesError error0.)
, console shows:
14/07/16 11:00:46,497 com.apple.CoreSimulator.CoreSimulatorService[336]: Error Domain=LaunchServicesError Code=0 "(null)" UserInfo={Error=PackageInspectionFailed, ErrorDescription=Failed to load Info.plist from bundle at path /Users/<redacted>/Library/Developer/CoreSimulator/Devices/906E713E-095D-458D-914A-2A3873723F0A/data/Library/Caches/com.apple.mobile.installd.staging/temp.UiQK9u/extracted/Payload/<redacted>.app/Frameworks/BNRCoreDataStack.framework}
Have tried to reboot, delete derived data, clean build. Inspected the BNRCoreDataStack.framework
in the .ipa after archiving, the Info.plist file seems to exist there.
If someone could shine some light on me why this is happening, that would be really great.
Is it possible to create the stack synchronously? I create it in app delegate and need to use it before any controller is created. Is it possible?
Move explicitly defined result types to a generic result such as https://github.com/antitypical/Result or a native either type if added by Apple
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))
})
The 2.0.0 podspec needs to be published.
The pod lint is failing around the @available
with regards to the use of entity()
-> BNRCoreDataStack (2.0.0)
- ERROR | [tvOS] xcodebuild: Returned an unsuccessful exit code. You can use `--verbose` for more information.
- ERROR | [tvOS] xcodebuild: BNRCoreDataStack/Sources/NSManagedObject+FetchHelpers.swift:29:31: error: 'entity()' is only available on tvOS 10.0 or newer
- NOTE | [tvOS] xcodebuild: BNRCoreDataStack/Sources/NSManagedObject+FetchHelpers.swift:29:31: note: add 'if #available' version check
- NOTE | [tvOS] xcodebuild: BNRCoreDataStack/Sources/NSManagedObject+FetchHelpers.swift:29:31: note: add @available attribute to enclosing static method
- NOTE | [tvOS] xcodebuild: BNRCoreDataStack/Sources/NSManagedObject+FetchHelpers.swift:29:31: note: add @available attribute to enclosing extension
An earlier pre-release version of CocoaPods had this fixed, as I was able to validate the pod spec before merging into master, however now its unable to pass and cannot be published.
We'll wait and see when this is resolved on CocoaPods side so we can publish the spec. In the meantime you should be able to specify the tag or master
if you need to use the Swift 3.0 version right away.
You can put CONTRIBUTING.md, ISSUE_TEMPLATE.md, and PULL_REQUEST_TEMPLATE.md files in .github/
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
Would it be a better idea to put all those very usefull functions in a straightforward:
extension NSManagedObject {
}
Either way, I would like to be able to use the useful functions you implemented in CoreDataModelable.
Compile error:
Getter for 'entityName' with Objective-C selector 'entityName' conflicts with method 'entityName()' from superclass '_Region' with the same Objective-C selector
Xcode 7.3.1, Mogenerator 1.29, BNRCoreDataStack 1.2.5, Swift 2.2.
Thanks for contributing to the CoreDataStack!
The Swift 2 compiler seems to have trouble identifying the types of errors that can be thrown from saveContextAndWait(), so when I call it, I must have a catch-all clause at the end of my error handling, like this:
do {
moc.saveContextAndWait()
} catch let error as NSError {
// do stuff with expected NSError
} catch {
// do nothing?
}
Should we have a more specific ErrorType enum that encapsulates the system errors?
NSFetchedResultsController provides sectionIndexTitles and sectionIndexTitleForSectionName(). How do we access those when using FetchedResultsController?
Hi everyone! I need a way to construct CoreDataStack SQLite type without dispatching. Is it possible right now?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.