Saving custom class to Core Data - core-data

I have a class called "Date" that I create in my app. I want to save newly created Date objects to Core Data, but I am getting
Property cannot be marked #NSManaged because its type cannot be
represented in Objective-C
Here is my model code:
import UIKit
import CoreData
#objc(MyModel)
class MyModel: NSManagedObject {
#NSManaged var dateObject: Date
}
I don't know enough about Core Data yet to understand how to do this without using NSManaged (if that's indeed the solution.) Can someone help, at least by pointing me in the right direction for where to read more about this- a solution would of course be better :).
Thanks.

Try:
#NSManaged var dateObject: NSDate?

Related

MagicalRecord how to setup for new Swift Project using CocoaPods Use :branch => 'develop' i.e. 2.3.0-beta.5

I've set up a new project to investigate Core Data with MagicalRecord compatibility. I'm specifying the 'develop' branch in the CocoaPod but I'm having issues with fetchRequests both using MyProjectName.MyManagedObject.MR_fetchAllSortedBy and MyManagedObject.MR_fetchAllSortedBy. I've created the MyManagedObject as a Swift file and the -ObjC flag is set in the other linker flags. The error seen is: 'NSInvalidArgumentException', reason: 'A fetch request must have an entity.'
The CoreData stack is set up successfully. The failure occurs within MagicalRecord at the fetch request.
Specifying #objc(<class name>) prefix for your NSManagedObject class will fix executeFetchRequest:error: A fetch request must have an entity. error when fetching entity.
import Foundation
import CoreData
#objc(AccountEntity) class AccountEntity: NSManagedObject {
#NSManaged var createdAt: NSDate
#NSManaged var name: String
}

CoreData: warning: Unable to load class named

I am duplicating an existing Objective-C TV Show app to a new Swift version using Xcode 6.1 and am having some issues with CoreData.
I have created a model of 4 entities, created their NSManagedObject subclass (in Swift), and all files have the proper app targets set (for 'Compile Sources').
I am still getting this error whenever I try to insert a new entity:
CoreData: warning: Unable to load class named 'Shows' for entity
'Shows'. Class not found, using default NSManagedObject instead.
A few comments:
When saving to Core Data, I use the parent-child context way to allow background threading. I do this by setting up the ManagedObjectContext using:
lazy var managedObjectContext: NSManagedObjectContext? = {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
let coordinator = self.persistentStoreCoordinator
if coordinator == nil {
return nil
}
var managedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.MainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
and by saving data using:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
var context = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.PrivateQueueConcurrencyType)
context.parentContext = self.managedObjectContext!
...rest of core data saving code here...
})
This warning is one of the quirks we have to deal with while the details of the Swift implementation are being ironed out. The warning occurs spuriously, i.e. your setup might work even if you do not follow the steps outlined below.
I have been able to get rid of it in most cases by making sure that the class is set correctly in the model editor. Unlike in many other SOF posts (including answers to this question), the suggestion to include the module name (like MyApp.Shows) has not helped me.
Make sure you check these three items:
1.
Version that works up to Xcode 7 beta 3
Notice that I corrected your entity name to the more appropriate singular.
Version that works for Swift 2.0 in Xcode 7.1
(Should work for Xcode 7 beta 4 and above)
You need to delete the text "Current Product Module" in Module!
2.
You should also follow the frequent recommendation to include
#objc(Show)
just above your class.
Note: If you are using Xcode 7 beta 4 or later, this step is optional.
3.
Also make sure to cast the created managed object to the proper class, as the default would be just NSManagedObject.
var newShow = NSEntityDescription.insertNewObjectForEntityForName("Show",
inManagedObjectContext: context) as Show
SWIFT 2 / XCODE 7 Update:
This issue (see my April 3 comment on this answer as well) is resolved in Swift 2 and XCode 7 beta release by Apple.
So you actually now do not need #objc(myEntity) in Swift as answered by Mundi or using
"MyAppName." before your Class name. It will stop working. So remove these, just put Class name in File and select Current Working Module as Module
and cheers!
But for those using #objc(myEntity) in Swift (like me), you can use this other solution instead which works smoothly.
In the xcdatamodel correct class in. It should look like this:
Here you go. Module.Class is the pattern for CoreData in Swift and XCode 6. You will also need the same procedure when using Custom Policy class in Model Policy or other CoreData stuff. A note: In image, The Name and Class should be Car and MyAppName.Car (or whatever the name of your entity). Here, User is a typo.
When using Xcode 7 and purely Swift, I actually had to remove #objc(MyClass) from my auto-generated NSManagedObject subclass (generated from Editor > Create NSManagedObject Subclass...).
In Xcode 7 beta 2 (and I believe 1), in the model configuration a new managed object of type File is set to the Module Current Product Module and the class of the object is shown in configuration as .File.
Deleting the module setting so it is blank, or removing the full stop so the class name in configuration is just File are equivalent actions, as each causes the other change. Saving this configuration will remove the error described.
In Xcode 6.1.1 you do not need to add the #objc attribute since the base entity is a subset of an objc class (NSManagedObject) (see Swift Type Compatibility. In CoreData the full Module.Class name is required. Be aware the Module name is what is set in Build Settings -> Packaging -> Product Module Name. By default this is set to $(PRODUCT_NAME:c99extidentifier) which will be the Target's name.
With xCode 7 and Swift 2.0 version, you don't need to add #objc(NameOfClass), just change the entity settings in "Show the Data Model Inspector" tab like below -
Name - "Your Entity Name"
Class - "Your Entity Name"
Module - "Current Product Module"
Code for Entity class file will be like (in my code Entity is Family) -
import UIKit
import CoreData
class Family: NSManagedObject {
#NSManaged var member : AnyObject
}
This example is working fine in my app with xCode 7.0 + swift 2.0
Do not forget to replace PRODUCT_MODULE_NAME with your product module name.
When a new entity is created, you need to go to the Data Model Inspector (last tab) and replace PRODUCT_MODULE_NAME with your module name, or it will result a class not found error when creating the persistent store coordinator.
You also need to use (at least with Xcode 6.3.2) Module.Class when performing your cast for example:
Assuming your module (i.e. product name) is Food and your class is Fruit
let myEntity = NSEntityDescription.entityForName("Fruit", inManagedObjectContext: managedContext)
let fruit = NSManagedObject(entity: myEntity!, insertIntoManagedObjectContext:managedContext) as! Food.Fruit
Recap:
Include module name when defining entity in Data Model Editor (Name: Fruit, Class: Food.Fruit)
When accessing the entity in code (i.e.SWIFT), cast it with Module.class (e.g. Food.Fruit)
I also encountered a similar problem, follow these steps to resolveļ¼š
The parent is NSManagedObject, not NSObject
The module of an
entity is default, not "Current Product Module"
Changing the Entity Class name in the Data Model editor to correspond to the class in question and adding #objc(NameOfClass) to file of each NSManagedObject right above the class declaration solved this problem for me during Unit Testing.
Most of these answers still seem to apply in Xcode 14. However, my Swift NSManagedObject subclass is included in a custom framework. So what worked for me is: In that Entity inspector, in that Module field (see screenshot in answer by khunsan), type in the name of your framework, for example, MyFramework.
What worked for me (Xcode 7.4, Swift) is changing the class name to <my actual class name>.<entity name>
in the Entity inspector, 'Class' box.
My initiator of the Managed object subclass, looks like this:
convenience init(<properties to init>) {
let entityDescr = NSEntityDescription.entityForName("<entity class name>", inManagedObjectContext: <managed context>)
self.init(entity: entityDescr!, insertIntoManagedObjectContext: <managed context>)}
//init properties here
For Xcode 11.5: if Codegen property is class Definition, and if you are not getting a suggestion for the entity you created in xcdatamodel. Try to quit Xcode and reopen your project again. It works for me. This answer is only if you are not getting suggestions but if your file doesn't get generated try any above answer.

Adding attributes to parent class fields and properties

In my example to illustrate my use case I have a parent class that is purposely database agnostic (let's say I can't change the code of it for some reasons, because the class come from a commercial assembly or the .net framework or are auto generated by entity framework):
public class Father
{
public string Field1;
public string Field2;
}
Now I'd like to store an object derived from it into MongoDB (again, it's only for the example, there a lot of other use cases and my question has nothing to do with MongoDB):
public class Child:Father
{
public ObjectId Id;
public DateTime DateCreation;
}
But I'd like to add attributes to some elements of the father, like [BsonIgnoreIfNull], without overriding (they are not marked as virtual) or having to fully reimplement the Father in my Child class.
What would be the cleanest way to do this?
Thanks!

How can I know the class type of an abstract entity in a NSPredicate?

Using core data I'd like to fetch some data. My model uses some abstract entities, see attached picture, where QuantifiedIngredient is an abstract class.
I'd like to fetch Ingredient entities that have at least one RecipeQuantifiedIngredients, but in the middle is QuantifiedIngredient, which is an abstract class.
How can I do that, how can I test the actual type of an abstract class inside a NSPredicate? Any idea or suggestion?
The only clue I found was:
How can you reference child entity name in a predicate for a fetch request of the parent entity?
Would work a custom property in my QuantifiedIngredient to know if it is a RecipeQuantifiedIngredient? For instance isRecipeQuantifiedIngredient?
Thanks a lot for your help.
If recipe is required in RecipeQuantifiedIngredient, you could try to make a fetch, that checks, if there is any ingredient.recipe. I think, that will work.
The custom property, in kind of flag, will work for you too. You'll just need to set and unset it whenever you add or delete all the recipeQuantifiedIngredient.
I don't want to take the time to translate this into CoreData-speak so here is my thought in SQL:
SELECT * FROM quantifiedIngredients WHERE recipe <> NULL
or something like that. This is essentially Nikita's suggestion of using a flag, except that the 'flag' is the existence of a property. I don't know how CoreData will react when faced with GroceryQuantifiedIngredients that don't have the recipe, I think KVO will throw an exception. You might be so bold as to add a category:
#interface GroceryQuantifiedIngredients (KVOHack)
-(id)recipe;
#end
#implementation GroceryQuantifiedIngredients (KVOHack)
-(id) recipe { return nil; }
#end
This would of course require CoreData to enumerate all quantifiedIngredients, but I presume it will have to do so anyway, and a the return nil should optimize into tiny code. The other consideration is whether this will have a bad effect on the rest of your code; you will have to make that call.
Another idea which pops to mind as I finish this up is to do something like this (I'm getting really loose with my pseudo-code now):
SELECT * FROM quantifiedIngredients WHERE [i respondsToSelector:#selector(recipe)];
See what I mean? I forget whether CoreData lets you play with some kind of cursor when working with predicates or fetchedThingamabobbers, if it does than I think this is your best bet. Anyway it's Sunday afternoon so that stuff is left as a exercise for the reader.
+1 for a good question.

groovy domain objects in Db4O database

I'm using db4o with groovy (actually griffon). I'm saving dozen of objects into db4o objectSet and see that .yarv file size is about 11Mb. I've checked its content and found that it stores metaClass with all nested fields into every object. It's a waste of space.
Looking for the way to avoid storing of metaClass and therefore reduce the size of result .yarv file, since I'm going to use db4o to store millions of entities.
Should I try callConstructors(true) db4o configuration? Think it would help?
Any help would be highly appreciated.
As an alternative you can just store 'Groovy'-beans instances. Those are compiled down to regular Java-ish classes with no special Groovy specific code attached to them.
Just like this:
class Customer {
// properties
Integer id
String name
Address address
}
class Address{
String street;
}
def customer = new Customer(id:1, name:"Gromit", address:new Address(street:"Fun"))
I don't know groovy but based on your description every groovy object carries metadata and you want to skip storing these objects.
If that is the case installing a "null translator" (TNull class) will cause the "translated" objects to not be stored.
PS: Call Constructor configuration has no effect on what gets stored in the db; it only affects how objects are instantiated when reading from db.
Hope this helps

Resources