I have a Core Data Entity with a Date attribute (e.g. current_date. Technically, in the Class which Core Data generates for that Entity, this attribute is optional (#NSManaged public var current_date: Date?). However, in my app this Date is always provided, which is why in the View I am displaying this fetched Entity via a list, I am force unwrapping it with current_date!. This all works fine so far. However, I have added an onDelete to that list to be able to delete single elements and now I am getting a bug Fatal error: Unexpectedly found nil while unwrapping an Optional value. Seems to be some problem related to the deletion process - as said, that value in the data is actually never empty. Does anyone know what is the problem here?
Your code may not set current_date to nil. But if you
Delete a managed object object
Save changes
Try to use that same managed object reference
...then current_date is nil, because that's something Core Data does. This error message suggests that you are attempting to use the object after deleting it and saving changes. Ideally you should fix that, because you won't have valid data anyway. You should also avoid force-unwrapping anyway, because using it is a way of specifically requesting app crashes any time you use it.
Related
I have a core data entity named Film which has properties title and date. I noticed that the generated NSManagedObject subclass contains optional NSManaged properties even though I marked the properties as non optional in the core data inspector.
Can I can manually change it as non-optional property or is it a better choice to leave it as optional? Why?
"Optional" means something different to Core Data than it does to Swift.
If a Core Data attribute is not optional, it must have a non-nil value when you save changes. At other times Core Data doesn't care if the attribute is nil.
If a Swift property is not optional, it must have a non-nil value at all times after initialization is complete.
Making a Core Data attribute non-optional does not imply that it's non-optional in the Swift sense of the term. That's why generated code makes these properties optional-- as far as Core Data is concerned, it's legal to have nil values except when saving changes.
Update: After writing this answer I wrote a deep dive blog post explaining things in more detail: https://www.atomicbird.com/blog/clash-of-the-optionals/
This is a known issue. Some people change it to non-optional with no adverse effects, I keep it the way it was generated and hope for early fix.
It always helps if you submit a bug to Apple to increase visibility and priority.
Create managedobject class and change the entity class type to manual and add these classes to your project scope.
Edit your managedObject to make them non-optional. This means you need to maintain this class yourself and do any changes both in the core data model and the class
If your data model is stable and won't be changed then you can use this.
The Optional checkbox in the data model inspector has nothing to do with Swift optionals. The checkbox determines whether or not the attribute is required to have a value.
If you deselect the Optional checkbox for an attribute, you must give that attribute a value or you will get an error when saving. By selecting the Optional checkbox you can save without giving the attribute a value. Suppose you have a description attribute that's a string. If you select the Optional checkbox you could leave the description blank and still save the entity.
Here's another example. Suppose you have text fields to let a person enter their home, work, and cell phone numbers. These phone numbers should be optional attributes. You wouldn't want to require someone to have a home phone number, a work phone number, and a cell phone number just to save the person's data.
Started working with booleans trying to save them within core data and figured I could do a simple true/false save object but after reading I am unsure of whether or not they added the ability to do this in swift or not. I read another post Swift + CoreData: Can not set a Bool on NSManagedObject subclass - Bug?. Reading through it led me to believe that they changed this so that it should be able to save simple booleans based on the edit from the first answer.
So I created the class with Bool instead of NSNumber, and tried to set the object true and save the object. It doesn't seem to work. So my question is do you have to set the object with NSNumber still?
The issue I am facing is that when I try to recall the data using a fetch request after saving the Bool as true, with the default value set to No which should = false if I understand correctly, I should be able to recall which attribute is true through the getter that I created as a var that loops to check what the object is and returns it as a string. This however isn't working.
How can we validate the context before saving it to core data?. My idea is i should have some validation before saving it into core data, if the values doesn't satisfy the validation the the coredata should not save the values. Say for example i have attributes like name, class, age, etc for entity candidate. I should have a validation that the values shouldn't be nil. If it is nil then the other values should not be saved.
Can anybody help me in this regard
EDITED:
I need to check them only at the time of saving and that should be done with core data
I like to do catchall validation in the save routine. Before you actually do the call to save the context, loop through its insertedObjects array and make sure they are as you require. If they aren't, you can either delete them or alert the user that they need to complete something (if the latter, return out of the method; give the user a chance to fix the problem).
Other validation should be at the point of entry, when you are getting values from, say, a textfield or checkbox to assign to your managed objects. Let the user know right away if there's a problem.
Also check out NSNumberFormatter, which can be applied to fields, preventing user from making incorrect entries to begin with.
Coredata validate itself when inserting its values. In managedObject class we can write our custom validation so that coredata will check that validation before saving the values. If the value is not valid then those values in the context will not be saved to coredata.
Here i added
#interface
-(BOOL) validateForInsert:(NSError **)error;
#implementation
-(BOOL) validateForInsert:(NSError **)error {
// check the value of the field with validation
if(condition == true) {
return Yes;
}
return NO;
}
(NSError **) is a special parameter that makes the coredata to call this method as if like a delegate method
Sorry, I hadn’t read your question carefully enough when I made that first answer. You’re not validating that individual entries for individual attrs are correct, rather, that no changes should be saved unless all attrs are filled for that object.
Looking at Apple doc “Model Object Validation”, you are concerned with inter-property validation, not property validation, and you are on the right track to be thinking of using validateForInsert: for this purpose.
That doc also supplies examples. Here’s a possible implementation for the particular entity you describe:
- (BOOL)validateForInsert:(NSError **)error {
if (self.name && self.class && self.age)
return [super validateForInsert:error];
else
return NO;
}
However, this method happens at the insertion stage, not at the save stage.
If you are gathering entries for a new entity all at once, validating at the insertion stage would make sense — don’t add a new object to the context if that object is doomed to be discarded as incomplete.
If you are gathering entries for changes to an existing object, and you want to make sure that all those changes work together before accepting any of them, validateForUpdate: would make sense — but there would be no way to restore the object to its original state other than by reopening the context without saving, unless you had cached its original values elsewhere.
If you want to gather attrs individually and wait to check that they are all complete before saving the object, I think you would do as I first suggested: Loop through the context’s insertedObjects and take care of validation before actually saving the context. There’s no existing validateForSave: method to override, but you could add one.
You could also combine these techniques: Gather entries and make new objects without inserting them, but cache all these objects in an array. When it comes time to save, loop through the cache and insert the objects into the context only if they pass validateForInsert:; then save the context.
Obviously I’m learning along with you, so the above might not be quite the cookie. Hopefully that Apple doc will be enough to get you started.
I was having problems adding objects to one of my core data objects that has a relationship and after doing some investigating I realized it was because that objects managedObjectContext was nil (0x0). Some more investigating revealed that anytime I created an object of that type, the managedObjectContext was always nil. Every object I create of any other type has the correct managedObjectContext. And no, the object was not deleted, this is immediately after calling NSEntityDescription:insertNewObjectForEntityForName:inManagedObjectContext
Why would only this particular object be broken? It's also strange that even though the managedObjectContext seems to be nil, it otherwise works correctly (other than the relationship problem). I've tried resetting the simulator several times and I've even regenerated the .h and .m files that core data produces for that object but I can't get it to work. As far as I can tell, there are no errors, the managedObjectContext just never gets set.
I figured it out. I had added a member variable called managedObjectContext, which I instinctively add to most classes in my application since I pretty much always need it. What I didn't realize is that I was overriding the methods of the same name in the parent class NSManagedObject. That's why it was reset to be nil and still worked until I tried to add relationship which queried the managedObjectContext, found it to be nil, and complained.
Whenever I use setPropertiesToFetch on an NSFetchRequest, the objects that are returned appear to all be faulted. They return YES to isFaulted and when displaying them in the console they appear like this:
< MyEntity: 0x5884850> (entity: MyEntity; id: 0x5886180 <x-coredata://4D96A1CB-187C-4D92-A50C-D639F7E69114/MyEntity/p197> ; data: <fault>),
Whereas if I don't set properties to fetch, every object's properties are visible in the console. Any idea why this is happening?
I've got an answer from the Apple Developer Forums:
https://devforums.apple.com/message/152330#152330
"The object being a fault means it might require a trip to the database, or it may mean that the object is pending lazy initialization and all the necessary data is cached. Tracking your app with the Core Data template in Instruments is the best way to empirically tell the difference.
For setPropertiesToFetch, you are intentionally not fetching all the properties, so you end up with a partial fault. Accessing some properties (the ones you told it to fetch) will work, and accessing others will require a round trip to the database. -isFault is a boolean, so most of the framework treats partial faults like they are just faults."
By default, Core Data will fetch objects as faults the first time they're loaded into the managed object context. It won't populate the attributes until you ask for them. If you need a fetch request to return non-faulted objects, you can use setReturnsObjectsAsFaults:YES
The documentation says that the value from -setPropertiesToFetch: is only used when resultType is set to NSDictionaryResultType.