Error Making Entity Relationship Encodable - swift

I'm trying to get a simple NSManagedObject class to conform to Encodable so that I can easily encode it to JSON.
I have an entity named TestObject that has a one to many relationship with an entity named Device.
Everything works fine until I try to encode an NSSet (to many relationship).
import UIKit
import CoreData
import Foundation
#objc(TestObject)
public class TestObject:NSManagedObject,Encodable
{
#nonobjc public class func fetchRequest() -> NSFetchRequest<TestObject> {
return NSFetchRequest<TestObject>(entityName: "TestObject")
}
#NSManaged public var testName: String?
#NSManaged public var devices: NSSet? // of entity type "Device"
enum CodingKeys: String, CodingKey {
case testName
case devices
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy:CodingKeys.self)
try container.encode(testName,forKey:.testName)
try container.encode(devices,forKey:.devices)
}
}
The error I receive from the compiler is
reference to member 'devices' cannot be resolved without a contextual type
try container.encode(devices,forKey:.devices)
What is this compiler telling me and how can I encode my objects along with its relationships?

Related

How do I access a Swift String enum in Objective-C?

I've got the following swift autogen model, that i can't change
#objcMembers public class Device: NSObject, Codable {
public enum Auth: String, Codable {
case enabled = "ENABLED"
case supported = "SUPPORTED"
case notSupported = "NOT_SUPPORTED"
case bypassed = "BYPASSED"
}
public var auth: Auth
public var brand: String
}
I'm trying to access the enum property in my Objective-C class like this
self.isAuthEnabled = ([Device.auth.rawValue isEqualToString:#"ENABLED"]);
but I keep getting this error, Property 'auth' not found on object of type 'Device' even though I have access to the brand property, I can't access the enum

Repeating reference to CoreData Entity when debugging object in Swift

I may be simply understanding this incorrectly, but when I created an Exercise entity and looked at it contents in the debugger I get this repeating reference to the Entity type.
The Exercise+CoreDataProperties file is standard:
import Foundation
import CoreData
extension Exercise {
#nonobjc public class func fetchRequest() -> NSFetchRequest<Exercise> {
return NSFetchRequest<Exercise>(entityName: "Exercise")
}
#NSManaged public var exerciseDuration: Int16
#NSManaged public var repeatNo: Int16
#NSManaged public var restDuration: Int16
#NSManaged public var exerciseName: String
#NSManaged public var id: UUID
#NSManaged public var associatedWorkout: NSSet?
}
// MARK: Generated accessors for associatedWorkout
extension Exercise {
#objc(addAssociatedWorkoutObject:)
#NSManaged public func addToAssociatedWorkout(_ value: WorkoutSet)
#objc(removeAssociatedWorkoutObject:)
#NSManaged public func removeFromAssociatedWorkout(_ value: WorkoutSet)
#objc(addAssociatedWorkout:)
#NSManaged public func addToAssociatedWorkout(_ values: NSSet)
#objc(removeAssociatedWorkout:)
#NSManaged public func removeFromAssociatedWorkout(_ values: NSSet)
}
extension Exercise : Identifiable {
}
And here is the xcdatamodeld config:
Any ideas why I cannot view the values of the object in debug mode once I've created it? Have I done something in my code to cause this repetition?
The variables view you're using can't see into the values of properties of managed objects (or of most objects). If you want to inspect the property values, use the debug console. When you're stopped on the line in your screenshot, you should be able to use po newExercise to see properties of newExercise, or you can use commands like po newExercise.exerciseName to see individual property values.

SwiftUI 1.0: Save custom Datatype in CoreData

I in my current project I want to save a custom data type in core data but I don't know to do it.
The Core Data Entity:
extension WorkoutBuy {
#nonobjc public class func fetchRequest() -> NSFetchRequest<WorkoutBuy> {
return NSFetchRequest<WorkoutBuy>(entityName: "WorkoutBuy")
}
#NSManaged public var beschreibung: String?
#NSManaged public var dauerInterval: Int64
#NSManaged public var dauerPause: Int64
#NSManaged public var dauerPauseDurchgang: Int64
#NSManaged public var durchgaenge: Int64
#NSManaged public var id: UUID?
#NSManaged public var intensitaet: String?
#NSManaged public var name: String?
#NSManaged public var price: Double
#NSManaged public var catagory: Catagory? !!!//here is my own data type !!!
}
extension WorkoutBuy : Identifiable {
}
My own data type:
struct Catagory: Codable, Identifiable{
let id: Int
let localizedString: String
let engishName: String?
}
When I do it this way I get this error:
Property cannot be declared public because its type uses an internal type
And:
Property cannot be marked #NSManaged because its type cannot be represented in Objective-C
Does anyone have a solution? Thank you in advance.
PS: I use the AppDelegate to create the persistentContainer
EDIT
When Catagory is a own core data entity the app is starting but when I add an object I got the following error like 10 times in the console:
2020-12-04 21:58:31.586858+0100 IntervallTraining[4869:1923447] [error] error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x2812c9380> , threw while encoding a value. with userInfo of (null)
CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x2812c9380> , threw while encoding a value. with userInfo of (null)
Ein Core Data-Fehler ist aufgetreten.

RealmSwift: storing an element with a timestamp

I am trying to define a wrapper around objects I want to store in Realm. The wrapper should contain an additional date object so that I can filter old objects. So far I have this
public final class RealmDateTaggedRealmObject: ObjectFacade {
#objc public dynamic var date: Date?
#objc public dynamic var value: ObjectFacade?
#objc private dynamic var id: String = ""
public override class func primaryKey() -> String? {
return #keyPath(id)
}
public convenience init<T: RealmMappable>(from object: RealmDateTagged<T>) {
self.init()
date = object.date
value = object.value.asRealmObject
id = object.primaryKey
}
}
The RealmMappable protocol enables transforming implementing entities into ObjectFacade. The ObjectFacade class is an empty class that inherits from Object, because I got an exception if I declared
#objc public dynamic var value: Object?
So I tried to be smart and created ObjectFacade. Turns out I'm not so smart cause it always stores nil. Also, value can't be a generic type because it is not supported in Objective-C.
Any suggestions?
Thanks!

Why does accessing a String parameter of a subclassed NSManagedObject with a parent relationship crash?

I have generated classes for two core data entities. The first is called Address and is an abstract entity. The second is called Person, and it inherits from Address. I've added a few example managed attributes for the purpose of this test. And i've added a non-managed String property to the Person class. Accessing the string property of the Person class will crash. Why does this crash?
The Address and Person classes are automatically generated by Xcode, with the exception of the extra parameter: let foo = "Foo"
If i modify the code to make Person inherit from NSManagedObject directly instead of Address, then the code works and doesn't crash.
Automatically generated Address class:
#objc(Address)
public class Address: NSManagedObject {
}
extension Address {
#nonobjc public class func fetchRequest() -> NSFetchRequest<Address> {
return NSFetchRequest<Address>(entityName: "Address")
}
#NSManaged public var street: String?
#NSManaged public var city: String?
}
Automatically generated person class with the exception of the "foo" parameter:
#objc(Person)
public class Person: Address {
public let foo = "Foo" //added this parameter
}
extension Person {
#nonobjc public class func fetchRequest() -> NSFetchRequest<Person> {
return NSFetchRequest<Person>(entityName: "Person")
}
#NSManaged public var name: String?
}
problem code
let person = Person(context: context)
print(person.foo) //doesn't crash, but prints empty line instead of value
print("VALUE:\(person.foo):") //crashes with Thread 1: EXC_BAD_ACCESS (code=1, address=0x18)
UPDATE:
if foo is defined as
public let foo: String? = "Foo"
then the print statements don't crash, instead they interpret the value as 'nil' and print that.
So my question becomes: Why is this value which is assigned as a constant being reset to nil under the covers?
I have two hand-waving explanations why you are getting nil:
Managed objects don't function very well until they are inserted.
Your foo is a what I would call a constant stored property. I made up the name because, red flag, I cannot find any examples of it in the Swift book chapter on Properties
Put these two together and you get an edge case that doesn't work.
That being said, I'm kind of surprised that your foo setting does not work, because foo is not a managed property (that is, it is not in the data model). If I make such a constant stored property in a regular, non-managed object…
public class Animal {
public let foo: String! = "Foo"
}
it reads back later as expected.
So, if you can accept that this edge case just doesn't work in Core Data, you can move on to several more normal ways that do work.
One way is to declare foo as a var and assign a value to in awakeFromInsert() which is, as I alluded to earlier, after insertion. In Core Data, awakeFromInsert() is one of your friends…
#objc(Person)
public class Person: Address {
public var foo: String!
override public func awakeFromInsert() {
foo = "Foo"
}
}
Another way that works is as a computed property…
#objc(Person)
public class Person: Address {
public var foo : String { return "Foo" }
}
And, finally, the most logical way, since foo is constant for all instances, is to make it a type property…
#objc(Person)
public class Person: Address {
static var foo: String = "Foo"
}
but of course if you do this you must reference it as Person.foo instead of person.foo.