0

In Core Data, attributes of type String and Int32 are "Optional" (ticked in properties).

enter image description here

Corresponding to these values in code, are the same types as optionals.

        var color1: String?
        var color2: String?
        var color3: String?
        var colorRangeLoc1: Int32?
        var colorRangeLoc2: Int32?
        var colorRangeLoc3: Int32?

Values are set in some cases, and passed to a function, as optionals, for transfer to Core Data.

func loadCellData(text: String, sortOrder: Int32, portion: Float, color1: String?, color2: String?, color3: String?, colorRangeLoc1: Int32?, colorRangeLoc2: Int32?, colorRangeLoc3: Int32?, colorRangeLen1: Int32?, colorRangeLen2: Int32?, colorRangeLen3: Int32?, underlineRangeLoc1: Int32?, underlineRangeLoc2: Int32?, underlineRangeLoc3: Int32?, underlineRangeLen1: Int32?, underlineRangeLen2: Int32?, underlineRangeLen3: Int32?)
{
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let context = appDelegate.persistentContainer.viewContext

    let entry: CellData = NSEntityDescription.insertNewObject(forEntityName: "CellData", into: context) as! CellData

    entry.text = text
    entry.sortOrder = sortOrder
    entry.portion = portion
    entry.color1 = color1
    entry.color2 = color2
    entry.color3 = color3
    entry.colorRange1Loc = colorRangeLoc1
    entry.colorRange2Loc = colorRangeLoc2
    entry.colorRange3Loc = colorRangeLoc3
...

Xcode compiles without error for the String? values, color1, color2 and color3, but shows the following error for Int32? values:

Value of optional type 'Int32?' must be unwrapped to a value of type 'Int32'

This suggests that the optional Int32 in CoreData is demanding an unwrapped optional value (while the optional Strings are fine)? Is there a difference (it would help me to understand why), and if so how is it best managed?

Assigning 'nil' as a starting value does not work. Force unwrapping causes a crash if nil (of course). Is it necessary to check for all values of type Int32?

if colorRangeLoc1 != nil { entry.colorRangeLoc1 = colorRangeLoc1 }

Or should it be 'guard' or 'if let'?

DrWhat
  • 2,360
  • 5
  • 19
  • 33
  • 2
    You are encouraged to declare attributes non-optional as much as possible. Especially the scalar types work fine with `0` (or whatever) as default value – vadian May 28 '19 at 09:04
  • 1
    Apple recommends to not set number attributes to optional and instead use a default value. See [the documentation](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/KeyConcepts.html#//apple_ref/doc/uid/TP40001075-CH30-SW12) – Joakim Danielson May 28 '19 at 09:05
  • If that is the final answer, I guess I have to accept it. The values really are 'optional', so I wanted to use them throughout my code in the way otherwise encouraged. Any value, including 0, will need to be managed. Because 0 is a valid value in this case, should I assign 999 and look for such cases when bringing data in and out of Core Data? Is there a better way? – DrWhat May 28 '19 at 09:41
  • 1
    You should be able to set them as mandatory with a default value in your core data model but then modify the generated class and set the property to optional and have some custom logic to return nil if this value is set to the default value. Maybe for color a negative value could be used? – Joakim Danielson May 28 '19 at 10:31

2 Answers2

0

Optional values in CoreData are not the same as in Swift. As per the comments, for numbers at least, set a mandatory - impossible value - instead of nil, and check this when using the value.

DrWhat
  • 2,360
  • 5
  • 19
  • 33
0
public var parent: Int32? {
    get {
        willAccessValue(forKey: "parent")
        defer { didAccessValue(forKey: "parent") }
        return primitiveValue(forKey: "parent") as? Int32
    }
    set {
        willChangeValue(forKey: "parent")
        defer { didChangeValue(forKey: "parent") }
        guard let value = newValue else {
            setPrimitiveValue(nil, forKey: "parent")
            return
        }
        setPrimitiveValue(value, forKey: "parent")
    }
}
sibur
  • 101
  • 1
  • 3
  • Hi and welcome to stackoverflow, and thank you for your answer. Rather than just posting a block of code, can you give a short explanation to what the issue is you solved and how you solved it? This will help people who find this question in the future to better understand the issue and how to deal with it. – Plutian Jan 24 '20 at 11:23