Xcode Nsmanagedobject Subclass Contains Optionals When They Are Marked as Non-Optional

Xcode NSManagedObject subclass contains optionals when they are marked as non-optional

"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.

Swift + CoreData: Cannot Automatically Set Optional Attribute On Generated NSManagedObject Subclass

The optional checkbox in the Core Data Model Editor has been existing before Swift and its optionals where introduced. Apple states about it in its Core Data Programming Guide:

You can specify that an attribute is optional — that is, it is not
required to have a value. In general, however, you are discouraged
from doing so — especially for numeric values (typically you can get
better results using a mandatory attribute with a default value — in the
model — of 0). The reason for this is that SQL has special comparison
behavior for NULL that is unlike Objective-C's nil. NULL in a database
is not the same as 0, and searches for 0 will not match columns with
NULL.

Thus, using Swift and Xcode 8, optional checkbox is (still) not related to the fact that you defined your properties as optionals or not in your managedObject subclasses. And don't expect optional checkbox to have any impact on your NSManagedObject subclasses properties optional type when you create them using Editor > Create NSManagedObject Subclass.

That said, every time I need a property to have its optional checkbox checked in the Model Editor, I immediately put its NSManagedObject Subclass declaration as an optional.



Addendum

Mogenerator is able to automatically toggle your NSManagedObject subclass properties from non-optional to optional every time you change this option for each of your Entity's attribute in the Data Model Inspector and rebuild your project.

SwiftUI core data optional and non-optional properties

When you create your entity the default setting for Boolean and Double is to use scalar (primitive) types and they are non-optional because Objective-C (which is what Core Data is based on) can't handle optional scalar types.

This is how they are defined in code

@NSManaged public var boolean: Bool
@NSManaged public var number: Double

If you uncheck to use scalar type (Inspector Cmd-alt-0) then the underlying type would be NSNumber instead and they would be optional

@NSManaged public var number: NSNumber?
@NSManaged public var boolean: NSNumber?

How does Core Data codegen decide whether to make a property optional?

Core Data is still rooted in Objective-C. So the primitives (bool, int, float, etc.) will be non-optionals, and the objects will be optionals.

Some data can be either an object or a primitive. For example, someone's age could be a NSNumber or a NSInteger. If you prefer that such a variable be backed by a primitive, then you can check the scalar box for the property in your model.

Core data | automatically generated String and Date attributes are optional even when not marked in swift

Two options

  • Edit the MyManagedObject 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
  • Create a protocol (or sub class) with same attributes (you need to give them new names) but non-optional and implement this protocol in a separate extension to get and set original attributes and then use this protocol rather than MyManagedObject in your code.

If your data model is stable and won't be changed that much the first option is probably best.

Core Data optional attributes and properties with Swift rules

I think that if the Swift team at Apple would read your question, they would smile and say: "Good question! Another example of how Swift is helping developers to question and improve their code."

My approach to this is:

  1. Let Core Data be Core Data. Attributes can be null. If proper operation requires an attribute to be not null, you may wish to validate this prior to insertion. But, since Core Data is a persistence framework, I assume that these objects are being saved to the disk, and data from the disk should never be trusted … it could be corrupt, or some unforseen future version of your app or an app extension could either intentionally or unintentionally cause some attributes to be null.

  2. Let Swift be Swift. A major design goal of Swift was to protect you from such unexpected nulls. As you have recognized, force unwrapping is discouraged. Instead, use if let or guard let. These are explained in Apple's Swift book, although you can find dozens of blog posts like this one which are more to the point.

Swift Core Data Usage in Xcode

Answers:

  • Creating the subclasses manually treates the optionals not accurately. Check any attribute and remove the question mark in the class if it's non-optional in the model.

  • Scalar Swift optional types (Int?, Double?, Bool?) cannot be represented in Objective-C. I recommend to declare them as non-optional.

  • Never mind, it has no effect where the classes are located, the main thing is that the file name is black (valid) in the Project Navigator and the target membership is assigned correctly.

  • in the Codegen Manual / None case you are responsible that the types in the model match the types in the classes otherwise you could get unexpected behavior. Any change in the class must be done also in the model and vice versa. However you can replace suggested ObjC classes like NSSet or NSDate with native Swift types Set or Date without changing the type in the model.

Xcode generate NSManagedObject Subclass issue

So I also ran in this issue. You have to disable automatical code generation if you want to create the NSManagedObjects by yourself. So there are different ways. First way is go to your model and changed the Toolversion to xCode 7.3.
In every entity you can set the Codegen to Manual/None like in the Screenshot.
Clean your project, and try again!
I hope this was helpful.
Sample Image

Xcode 8 generates broken NSManagedObject subclasses for iOS 10

I finally got mine to work. Here is what I did. (Flights is one of my entities)

I setup the xcdatamodeld as follows

Sample Image

And then the entity as

Sample Image

Then I used Editor -> Create NSManagedObject Subclass

This creates two files for my flights entity

Flights+CoreDataProperties.swift

Flights+CoreDataClass.swift

I renamed Flights+CoreDataClass.swift to Flights.swift

Flights.swift is just

import Foundation
import CoreData

@objc(Flights)
public class Flights: NSManagedObject {

}

Flights+CoreDataProperties.swift is

import Foundation
import CoreData


extension Flights {

@nonobjc public class func fetchRequest() -> NSFetchRequest {
return NSFetchRequest(entityName: "Flights");
}

@NSManaged public var ...
}

This appears to work for me.I could not get Codegen to work in any other way, even though I tried many of the suggestions that were out there.

Also this had me scratching my head for a while and I add it as an assist. Don't forget with the new Generics version of the FetchRequest you can do this

let fetchRequest: NSFetchRequest = NSFetchRequest(entityName: "Flights")


Related Topics



Leave a reply



Submit