Is it Possible to put the whole CoreData-Stack in a framework? - swift

I have a very large Project and I am right in a refactoring session. At the beginning my idea sounds good to me, but now i am stuck and confused and near before a git rollback. You guys are my last chance.
We’ve done a GUI application that shows some data that are living in CoreData. A background Process is fetching data from time to time from the network and put them into the CoreData.
So I’ve got the request thing -> pushing into CoreData and <- getting it out onto the GUI.
That works for very good for us. It’s straight forward and nothing special. My Company is programming this application since January and the requesting and data part gets huge. We also have a 100% test coverage! \o/. Working in that project could be so nice… if… if the GUI things could be separated.
As time goes by I have to split the dev-team into two parts: one for the gui (and the several gui applications that all based on the same data model) The second one for the Request-and-CoreDate part. My Model interface is clean enough to have a nice entry point, so i thought i would be easy to move the Request and CoreData sections into a library-project in my Workspace.
hm, well. no!
I put the Kit.xcdatamodeld into the new library project. I generate all models and add all the code from the main application into the lib. I resolved every problem and start to move the first basic tests into the new project.
I put the managedObjectModel part from our ApplicationDelegate into a DataController in the new project. And changed the first call to use this managedObject from the new class.
let dc = DataController()
_ = GlobalScope(context: dc.managedObjectContext!)
When I run the first test that should store a simple entity than an error occurs in managedObjectModel:
lazy var managedObjectModel: NSManagedObjectModel = {
// The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model.
let modelURL = NSBundle.mainBundle().URLForResource(" <LibName>Kit", withExtension: "momd")!
return NSManagedObjectModel(contentsOfURL: modelURL)!
}()
fatal error: unexpectedly found nil while unwrapping an Optional value
My Question is: Is it possible to do the whole CoreData stuff into a Framework? I wan’t have any data model or requests in my gui applications? The plan ist to include the framework and use the getXY() setXY() functions of my models. Also the whole network background fetching should be places in the framework.
But it seams that there is no mainBundle in a framework. So how to get the database the right way?
Thank you very much.
ps

First, Core Data is already a framework. You are looking to put your layer on top of Core Data into a framework. Is it possible? Probably, but it is not a great idea.
There is no value in putting a third (or more) of your application into a framework. It will not make anything cleaner or easier. In fact it will make debugging of your application harder.
Separate out the code using groups in Xcode and call it there. Trying to put things into separate Xcode projects (which is what you would need) would lead to more issues than it is worth.
BTW, there is no way to compile the model into the framework as that is an independent file. Therefore your primary application would need to embed the model file anyway.
You could explore creating your own custom CocoaPod like structure but again, it really is not worth it and maintainability will decrease.

The problem is this line:
let modelURL = NSBundle.mainBundle().URLForResource(" <LibName>Kit", withExtension: "momd")!
It's looking in the main bundle for that resource, which doesn't exist. You'll want to use bundleWithIdentifier or bundleForClass instead, like:
let modelURL = NSBundle(identifier:"com.whatever.yourFrameworkIdentifier").URLForResource...

Related

Is there a way to use CoreML models in capacitor-plugins?

I am currently working on a capacitor plugin, that should allow me to run a CoreML-model on the ios-version of my Ionic-App.
Even though I used the common terminology to access the model-file, the model is somehow not found in my ios-plugin-script. Is there a different way I can access the model besides VNCoreMLModel or is there maybe in general a problem with using CoreML models in capacitor plugins?
I also tried to load the model, using the same lines of code in a full/native swift app, what worked fine.
The model is already located in the Plugins' Directory (together with the files Plugin.swift, Plugin.m and so on...) and is accessed via calling it as //VNCoreMLModel(for: "modelname".model).
The error message in particular is : "Cannot find 'Resnet50' in scope"
code snippet:
guard let model = try? VNCoreMLModel(for: Resnet50().model) else {return}
(I personally think, that when integrating the plugin into my app, the model file is maybe not transferred into the 'Development Pods' for any reason.)
I don't know what capacitor is, but Resnet50 is a class that is automatically generated by Xcode. You either need to copy the source code for that class into your own project, or not use that class and instantiate an MLModel object for your model instead.

I get a warning in my console when load data from Coredata

i have a small problem with my code. When I load data from my CoreData I get warnings in my consol but I don´t know why. I´m not a professional programmer and also google couldn´t really help me so now I´m here.
I load my data like this:
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var data: [DataToLoad] = []
override func viewDidLoad(){
do{
data = try context.fetch(DataToLoad.fetchRequest())
}catch{
print("error")
}}
But when I load it like that the console says...
"2020-09-05 20:32:04.884728+0200 Test-Application[3850:348569] [general] 'NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release"
...after I start the App.
So I mean everything is working fine, but where is my error that this massage appears.
I hope you can help me.
Sorry for my bad english I hope you can understand everything.
Have a nice day and thank you all.
The app is still working because it's a warning and not an error but it's good to not ignore warnings.
In your case, the warning occurs because NSKeyedUnarchiveFromData is deprecated. This means it's outdated and will be replaced in the future and the app might then stop working.
Kaira Diagne explains:
With iOS 12 Apple has started adopting NSSecureCoding across the entire platform. For Core Data this means that the default ValueTransformer, which uses NSCoding to transform a custom data type into a format that can be stored in the persistent store, at some point will change as well.
In your case NSSecureUnarchiveFromData instead of NSKeyedUnarchiveFromData in Core Data.
This means that the first thing we need to do is make sure that the data type of every transformable property in our data model conforms to secure coding.
(Link: NSSecureCoding and transformable properties in Core Data, 2020)
For your app to also work in the future you will have to dig somewhat deeper into the code and see where you are using the deprecated methods and classes and replace them.

Core Data Entities multiple build configurations

I have 3 build configurations, Debug, Release and Development. For Development I have created a new Scheme with a new bundleID, Product name etc so I can see which one is DEV and DEBUG on my phone.
I am using Core Data and for the DEBUG with the original bundleID everything works fine, but when I switch to use the Development one, I get an error when I try to create a new entity with name:
NSEntityDescription.insertNewObject(forEntityName: "MyEntity", into: managedContext)
The error I get:
Could not cast value of type 'NSManagedObject_MyEntity_' (0x600002d62b20) to 'AppName_DEV.MyEntity' (0x102bf9368).
It seems like it is trying to get the MyEntity class from my "AppName DEV" scheme not the "AppName". I can't find any Build Settings where I could point it to use the same model?
Any ideas on how to use core data with multiple build configurations?
Ok, I found the problem. Since I was trying to revive a very old app originally written in swift 2, it occurred to me that I might double check how was the data model created. After hours of tinkering with the core data set up process, I changed 2 things that finally get it to work.
1.) In the .xcdatamodeld file, on the right side in the Data Model Inspector, make sure that you have the Module field EMPTY I had my AppName Inside, which was the same as the original target name.
2.) I added #objc(EntityName) to the NSManagedObject subclass I had.
Of course I cleaned the project, deleted the app from the simulator and installed it again.
If you have an issue like that, hope that whis will help you, good luck!

Core Data Error

I am creating an application using Core Data. But When I run my app it crashes. It shows me this reason:
reason = "The model used to open the store is incompatible with the one used to create the store";
What should I do now?
I think you need to refer this link and refer to answer given by Grouchal in the link below:
What do I have to do to get Core Data to automatically migrate models?
If you need any further help please do let me know.
Hope this helps you.
It means that you created a model, run the app, modified the model (by adding or removing managed objects, renaming object properties and so on...) and reopened the app without migrating the data first. I still have to try this by myself but, you should definitely take a look here: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreDataVersioning/Introduction/Introduction.html
You can just delete the app (icon) from the simulator or device. Then, rebuild and run.
As dave explained, you have modified the core data structure (the store). If you're using the standard template, in the new rebuild a new model (NSManagedObjectModel) will be created that is compatible with your newly modified store.
You will probably be making many changes to the core data structure (adding or deleting an entity or some property or relationship), and, each time you do, you can just delete the app from the simulator or device.

UIManagedDocument example / tutorial

I have been trying very unsuccessfully to create a simple UIManagedDocument library style application (separate documents saved to iCloud).
I am confused with the following:
Do I subclass UIManagedDocument and set up the persistentStoreCoordinator, ManagedObjectModel & ManagedObjectContext within this subclass, or are these supposed to be configured within the AppDelegate (and if so, how do I go about refreshing the persistentStoreCoordinator to look at the new file - it seems that once that has read a persistentStore that I can't get it to read a new persistent store)?
Richard's example is an excellent example. I used it and the PragmaProg book on core data http://pragprog.com/book/mzcd2/core-data as a guide for creating my managed document module on github.
See: https://github.com/dtrotzjr/APManagedDocument
My code makes use of iOS 7 iCloud Core Data behavior which I cannot comment on publicly until the NDA is lifted. Feel free to ping me directly if you have any questions.
I've just posted a project based on Rick Warren's example: MultiDocumentPlusUUID. In his "Syncing Multiple Core Data Documents Using iCloud" post, Rick writes:
Another bug often shows up when I start trying to pass changes back and forth between devices that both have the same file open. The first sync always seems to work--and it seems to work pretty well as long as each subsequent sync is in the same direction.
MultiDocumentPlusUUID compiles and runs on iOS 7.1b4, and can ping-pong updates to a given document successfully.