Core Data Framework With Multiple Targets - core-data

I am currently making a project in swift 4 which uses a few targets. Since all the targets need to access the same core data, I have decided to make my own framework target which stores the data model for it as well as the access information for it.
The problem I am having is in my application target (CoreDataTest), when I run the application, I get the following error:
2017-09-17 12:02:20.787132+0100 CoreDataTest[22070:3218298] [error] error: Failed to load model named TestData
CoreData: error: Failed to load model named TestData
2017-09-17 12:02:20.787594+0100 CoreDataTest[22070:3218298] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'An NSManagedObject of class 'Message' must have a valid NSEntityDescription.'
*** First throw call stack:
(0x182097d38 0x1815ac528 0x18481a73c 0x1026c6678 0x1026c6708 0x1848bac5c 0x10261d480 0x10261ce94 0x10261cd48 0x10261cecc 0x18b42b96c 0x18b42b544 0x18b43210c 0x18b42f378 0x18b49edb4 0x18b68e570 0x18b693300 0x18b9129b4 0x18bbd90d0 0x18b912618 0x18b912e88 0x18c05daf4 0x18c05d998 0x18bde7ab4 0x18bf77c94 0x18bde7964 0x18bbd8730 0x18b691a44 0x18ba80144 0x18472d968 0x184736270 0x10344145c 0x10344db74 0x184761b04 0x1847617a8 0x184761d44 0x182040358 0x1820402d8 0x18203fb60 0x18203d738 0x181f5e2d8 0x183de3f84 0x18b48f5e0 0x10261deec 0x181a8256c)
libc++abi.dylib: terminating with uncaught exception of type NSException
I added an exception break point and it crashes in ViewController.swift at PersistenceStorage.saveContext().
How would I create a framework to create a shared Core Data database throughout my multiple targets in a single project?
Here is my project setup. Please note that each group is its own target.
Target: CoreDataKit (Framework)
CoreData.swift
import CoreData
public class PersistenceStorage {
private init() {}
public static var context: NSManagedObjectContext {
return persistentContainer.viewContext
}
public static var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "TestData")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
public static func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
Message+CoreDataClass.swift
import Foundation
import CoreData
#objc(Message)
public class Message: NSManagedObject {
}
Message+CoreDataProperties.swift
import Foundation
import CoreData
extension Message {
#nonobjc public class func fetchRequest() -> NSFetchRequest<Message> {
return NSFetchRequest<Message>(entityName: "Message")
}
#NSManaged public var text: String?
}
Target: CoreDataTest (Main Application)
ViewController.swift
import UIKit
import CoreDataKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let message = Message(context: PersistenceStorage.context)
message.text = "test"
PersistenceStorage.saveContext()
}
}
AppDelegate.swift
import UIKit
import CoreData
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
}

After a lot of research and trial and error, I found that I need to set the target members on the xcdatamodel file to the other targets that I wanted it to be shared with.

Just bumped into this myself so thought I'd post a couple other options.
Since you aren't subclassing NSPersistentContainer then it doesn't know where to look for bundles so has no option but to look in the main bundle.
If you want to only have your model in your framework then you could subclass NSPersistentContainer, or you can load the model first and pass that to the initialization of the persistent container. If you have only a single model then doing something like mergedModelFromBundles is pretty simple to do and then pass that model to the persistent container initializer.

Related

Jest is not covering super call in my custom error class

Well, I just created a custom error class, which extends the Error class, and I'm not directly testing that class, but it is being covered when I test other files that call my custom error.
However, in my constructor I had to call super(message) from Error, but it is not being covered by jest.
This is my error class code:
export class ApiError extends Error {
constructor(public statusCode: number, message: string) {
super(message);
this.name = 'ApiError';
this.statusCode = statusCode;
this.message = message;
Object.setPrototypeOf(this, ApiError.prototype);
}
static badRequest(message: string): ApiError {
return new ApiError(400, message);
}
static unauthorized(message: string): ApiError {
return new ApiError(401, message);
}
static forbidden(message: string): ApiError {
return new ApiError(403, message);
}
}
And this is the coverage report:
Just consider MongooseError.ts really similar to ApiError.ts, both are extending Error and calling super(message).
What should I do, since I'm not calling any method from super class?
PS.: I don't know what other code files I need to share, since the class is being tested on both controllers and also in some services.

SwiftUI Preview with Core Data: invalid NSEntityDescription

I'm trying to have my SwiftUI Previews work with an in memory Core Data Stack (from Xcode Template). As soon as I call Entity.entity(), I get the following error message:
let context = PersistenceController.preview.container.viewContext
let newBoatMO = Entity(entity: Entity.entity(), insertInto: context)
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'An NSManagedObject of class 'Entity' must have a valid NSEntityDescription.'
I checked in that the name in NSPersistentCloudKitContainer(name: is correct, I also checked in my .xcdatamodeld, the Entity name is correct, the module is empty (ie Global Namespace), and I have this #objc(Entity) at the top of my NSManagedObject subclass.
If I use the non-memory Stack, the Preview works. It's as if the Model was not loaded if I use the in-memory Stack.
For me this was fixed by using public convenience init(context moc: NSManagedObjectContext) rather then the designated public init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?).
So:
Entity(context: context)
instead of
Entity(entity: Entity.entity(), insertInto: context)
Some background:
I had this error when I had 'overridden' the default convenience init(context moc: NSManagedObjectContext). So I solved it by switching (back) to the built-in version.
Before my Location+CoreDataClass looked like this:
#objc(Location)
public class Location: NSManagedObject {
convenience init(context moc: NSManagedObjectContext) {
self.init(entity: Location.entity(), insertInto: moc) // <- Error
timestamp = Date()
}
}
and afterwards like this:
#objc(Location)
public class Location: NSManagedObject {
convenience init(into c: NSManagedObjectContext, timestamp: Date = Date()) {
self.init(context: c) // <- No error
self.timestamp = timestamp
}
}
I'm not sure what causes the error, but maybe this helps someone into the right direction.

CoreData bug in Xcode 12.1

I am working through Paul Hudson's 100 Days of SwiftUI and on Project 11 have hit a frustrating issue with CoreData. This is a direct lift of Paul's code that compiles and runs fine in his video. The Bookworm.xcdatamodeld has a single entity named Student that has two attributes: a UUID named id and a String named name.
It compiles fine, but running it results in a crash on the ForEach, with 'students' underlined in red. The error message that pops up in the console says:
2020-10-31 12:13:47.934507-0400 Bookworm[614:7766183] [error] error: No NSEntityDescriptions in any model claim the NSManagedObject subclass 'Bookworm.Student' so +entity is confused. Have you loaded your NSManagedObjectModel yet ?
CoreData: error: No NSEntityDescriptions in any model claim the NSManagedObject subclass 'Bookworm.Student' so +entity is confused. Have you loaded your NSManagedObjectModel yet ?
2020-10-31 12:13:47.934651-0400 Bookworm[614:7766183] [error] error: +[Bookworm.Student entity] Failed to find a unique match for an NSEntityDescription to a managed object subclass
CoreData: error: +[Bookworm.Student entity] Failed to find a unique match for an NSEntityDescription to a managed object subclass
2020-10-31 12:13:47.953419-0400 Bookworm[614:7766183] [SwiftUI] Context in environment is not connected to a persistent store coordinator: <NSManagedObjectContext: 0x6000008d0820>
I have searched a ton, and tried every recommended solution that I have found including: simply closing and reopening Xcode (Step 1), cleaning the project and then repeating Step 1, and deleting all the derived data and repeating Step 1. I have verified that Current Product Module is selected in the inspector for the Module, and that Codegen has Class Definition selected.
import SwiftUI
import CoreData
struct ContentView: View {
#Environment(\.managedObjectContext) var moc
#FetchRequest(entity: Student.entity(), sortDescriptors: []) var students: FetchedResults<Student>
var body: some View {
VStack {
List {
ForEach(students, id: \.id) { student in
Text(student.name ?? "Unknown")
}
}
}
}
}
If you are using SwiftUI lifecycle, you should initialize NSPersistentContainer in a parent View (or App) and import managedObjectContext to the environment.
In your case, it could be something like this:
import SwiftUI
import CoreData
#main
struct coreDataParadigmApp: App {
let persistenceController = PersistenceController.shared
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
}
}
}
struct ContentView: View {
#FetchRequest(entity: Student.entity(), sortDescriptors: []) var students: FetchedResults<Student>
var body: some View {
VStack {
List {
ForEach(students, id: \.id) { student in
Text(student.name ?? "Unknown")
}
}
}
}
}
// DONT FORGET TO CHANGE THE NAME OF YOUR FILE
struct PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentContainer
init() {
container = NSPersistentContainer(name: "coreDataNameOfFile")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
}
}

Having a SwiftUI Toggle control a Bool of a Core Data object causes a crash

I have a model called Note that is an NSManagedObject automatically generated by Core Data. It has a pinned property that is a non-optional Bool. I am trying to pass the Bool into a Toggle view, but this causes a crash:
2019-09-09 12:38:11.647030-0500 MyApp[12336:2688627] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Note pinned]: unrecognized selector sent to instance 0x2837e42d0'
*** First throw call stack:
(0x1a665897c 0x1a63810a4 0x1a655c42c 0x1a665cdf8 0x1a665ebdc 0x104f83cd4 0x1b37f0900 0x1b37f0528 0x1b37f02b8 0x1b37f2278 0x1dbcd19f0 0x1dc2aa43c 0x1dc2ab504 0x104f83bf4 0x1dbf41f30 0x1dbf42a64 0x104f83680 0x1dc2c4f98 0x104f826c4 0x1dbd8b484 0x104f82450 0x104f85124 0x1dbd158e4 0x1dbd16070 0x1d0600458 0x1d05e8a60 0x1d05e8d24 0x1d05eda0c 0x1dbe41838 0x1dbe41b64 0x1dbe418ec 0x1dc1a82bc 0x1dc1a7d24 0x1dc19e600 0x1dc32122c 0x1dc321258 0x1aaaed5e8 0x1acfd6460 0x1acfdac90 0x1aaad989c 0x1a9f891c4 0x1a9f86b7c 0x1a9f8b0cc 0x1aaae0080 0x1a9f8b000 0x1aa0817b0 0x1aa07e160 0x1aaadfe50 0x1aaab4e18 0x1aaab3cc4 0x1aaab1408 0x1aaae179c 0x1aaae1d28 0x1aaaacc88 0x1aaae22ec 0x1aaaac8a8 0x1aaaac344 0x1aa07a790 0x1aa0823d0 0x1aa18ea58 0x1aa082360 0x1aaadfd38 0x1aa0821c8 0x1a9f7a648 0x1aa66c3c4 0x1aa65bfec 0x1aa68bdc0 0x1a65d5c38 0x1a65d0b24 0x1a65d10f0 0x1a65d08ac 0x1b042b328 0x1aa662f00 0x104f716d0 0x1a645b460)
libc++abi.dylib: terminating with uncaught exception of type NSException
My view that contains the Toggle:
struct NoteInfo: View {
#Binding var note: Note
var body: some View {
NavigationView {
Form {
Section {
Toggle(isOn: $note.pinned) {
Text("Pinned")
}
}
}
}
}
}
Automatically generated Note code:
#objc(Note)
public class Note: NSManagedObject {
}
extension Note {
#nonobjc public class func fetchRequest() -> NSFetchRequest<Note> {
return NSFetchRequest<Note>(entityName: "Note")
}
#NSManaged public var modifiedAt: Date?
#NSManaged public var pinned: Bool
#NSManaged public var trashed: Bool
#NSManaged public var unsecuredContent: String?
}
This works for me:
import SwiftUI
struct TaskRow: View {
var task: Task
// States of the Task
#Binding var isCompleted: Bool
var body: some View {
HStack {
// Toggle
Toggle(isOn: $isCompleted) {
EmptyView()
}
// And so on...
}
}
}
import CoreData
import SwiftUI
struct TableView: View {
#EnvironmentObject var model: TasksViewModel
var body: some View {
List {
ForEach(model.items) { task in
TaskRow(task: task,
isCompleted: model.toggleCompletion(of: task))
}
}
}
}
import Combine
import CoreData
import SwiftUI
class TasksViewModel: NSObject, ObservableObject {
func toggleCompletion(of task: Task) -> Binding<Bool> {
let binding = Binding<Bool>(get: { () -> Bool in
return task.completedAt != nil
}) { (newValue) in
// This func updates the database
toggleCompletion(of: task, isCompleted: newValue)
}
return binding
}
}
Article on Medium - https://medium.com/#voevodin/swiftui-list-with-toggle-coredata-5eb6f52a390a
My bad, it turns out that somehow the pinned field of my Core Data model got deleted, but the generated code was out of sync with that, so this wasn't an issue with SwiftUI.

Error CS1061: AppDelegate does not contain a definition for GetNativeField

I'm writting my first iPhone app using mono touch. I have only written a little bit of code, and suddenly, it does not compile anymore, I get this error:
/MyRoute/MainWindow.xib.designer.cs(85,85): Error CS1061: Type xxxx.AppDelegate' does not contain a definition forGetNativeField' and no extension method GetNativeField' of typexxx.AppDelegate' could be found (are you missing a using directive or an assembly reference?) (CS1061) (xxx)
Any idea where this error comes from and how to solve it?
Thanks! :-D
Edited: Added aditional information:
THIS IS THE MAINWINDOW DESIGNER CODE:
namespace GuiaTeleIphone {
// Base type probably should be MonoTouch.Foundation.NSObject or subclass
[MonoTouch.Foundation.Register("AppDelegate")]
public partial class AppDelegate {
private MonoTouch.UIKit.UIWindow __mt_window;
#pragma warning disable 0169
[MonoTouch.Foundation.Connect("window")]
private MonoTouch.UIKit.UIWindow window {
get {
this.__mt_window = ((MonoTouch.UIKit.UIWindow)(this.GetNativeField("window")));
return this.__mt_window;
}
set {
this.__mt_window = value;
this.SetNativeField("window", value);
}
}
}
}
THIS IS THE MAIN.CS:
namespace GuiaTeleIphone
{
public class Application
{
static void Main (string[] args)
{
UIApplication.Main (args);
}
}
// The name AppDelegate is referenced in the MainWindow.xib file.
public partial class AppDelegate : UIApplicationDelegate
{
List<RSSChannel> RemoteChannelsData;
// This method is invoked when the application has loaded its UI and its ready to run
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
// If you have defined a view, add it here:
// window.AddSubview (navigationController.View);
window.MakeKeyAndVisible ();
// do things here
return true;
}
}
}
The other partial class of xxxx.AppDelegate is missing or in a different namespace. It specifies the base class.

Resources