3

I have a field stored on a core data object called "metadata" which is of type String (no optional, because Apple docs say not to mess with optionals in CD). Sometimes, the metadata field is nil. In checking whether this value is nil, I do the following check:

if object.metadata as String? != nil {
    ...
} 

However, my code continuously crashes on this line as an EXC_BAD_ACCESS. I have also tried:

if let metadata = object.metadata as String? {
    ...
}

Which doesn't work either. I cast objects successfully to optionals in other parts of my code, so I don't understand why this particular case isn't working. How do you check whether a core data property is a nil string?

user3781236
  • 728
  • 2
  • 9
  • 23
  • Might help to see more detail on the crash. Might have nothing to do with the casting but rather the object and its allocation. Also, when you say you've casted objects successfully in other parts of your code, are they also Strings? Is the crash every time? – shim Dec 10 '14 at 22:16
  • @shim yes - in fact, the exact same property. I have three objects with this property. The first two are not nil, and it passes fine. The last one is nil, and that's where it crashes – user3781236 Dec 10 '14 at 22:19
  • Maybe post the NSManagedObject subclass file? – shim Dec 10 '14 at 22:20
  • try `if let metadata = object.metadata as? String {...}` – Ian Dec 10 '14 at 22:24
  • `if let metadata = object.metadata as String? { }` *should* work, this is what a suggested in http://stackoverflow.com/a/25664102/1187415. Does it not compile, crash or how does it "not work"? – Martin R Dec 10 '14 at 22:52
  • @MartinR it compiles, but crashes with the same EXC_BAD_ACCESS error as above – user3781236 Dec 10 '14 at 23:00
  • Are you sure `object` exists? You'll get this crash if `object == nil`. Also please try doing `let metadata = object.metadata as String?` and then `if metadata != nil {` – Abhi Beckert Dec 10 '14 at 23:39

1 Answers1

5

It looks like what you really want is this:

if object.metadata != nil {
    ...
}

or this:

if let metadata = object.metadata as? String {
    // You can now freely access metadata as a non-optional
    ...
}

--EDIT--

My mistake, I didn't read the first part of your question thoroughly enough. It looks like the duplicate answer has a solution for this. Essentially, the generated managed object subclass is a bug and you should modify the properties to be either optional or implicitly unwrapped. You can check both of those using the first method for implicitly unwrapped and second for optionals.

There are several questions which discuss the issue of the generated subclasses not producing optional properties. I wouldn't be too concerned about editing the subclasses; there's nothing special about them except that Apple is making it easier to create them.

Check if property is set in Core Data?

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

--Edit2--

If you really don't want to touch the subclass you can access the property using valueForKey() and could add that as an extension if you wanted something a bit cleaner.

if let metadata = object.valueForKey("metadata") as String? {
    ...
}

In an extension:

extension ObjectClass {
    var realMetadata: String? {
        set {
            self.setValue(newValue, forKey: "metadata")
        }
        get {
            return self.valueForKey("metadata") as String?
        }
    }
}
Community
  • 1
  • 1
bjtitus
  • 4,231
  • 1
  • 27
  • 35
  • I already tried both. To the first, the error is: **Type 'NSString' does not conform to protocol 'NilLiteralConvertible'**. To the second, the error is: **Conditional downcast from 'String' to 'String' always succeeds** – user3781236 Dec 10 '14 at 22:34
  • Are you sure? Notice the question mark placement in his answer and my comment compared to the code you provided – Ian Dec 10 '14 at 22:37
  • and from the error you're getting on the second one, it sounds like object.metadata isn't an optional at all so if you provide your object class it could be useful to us helping you with your question – Ian Dec 10 '14 at 22:39
  • It seems that I also did not read the question thoroughly. OP's second attempt is exactly what I suggested in my answer to the "possible duplicate". Therefore I will reopen the question... – Martin R Dec 10 '14 at 22:50
  • @bjtitus - I've been told explicitly that I should not make changes to Core Data subclasses in swift, which was why I was trying to cast it as an optional after the fact. – user3781236 Dec 10 '14 at 22:51
  • @MartinR I don't believe that is the case, you suggest changing the properties type to an optional or non-optional. If he didn't change the type in the managed object subclass, he would be unable to cast it to an optional later. – bjtitus Dec 10 '14 at 22:52
  • @Bluehound - Yes, I'm sure I had tried out both of the options he listed above, neither of which worked. – user3781236 Dec 10 '14 at 22:52
  • So why do you need to cast it to an optional if it will never be an optional because it will alway be defined in the data model? – Ian Dec 10 '14 at 22:55
  • @Bluehound as I stated in my question, it won't always be defined. It's just that for some reason in Swift, when creating core data objects, it does not mark it as optional even when you mark it as optional – user3781236 Dec 10 '14 at 22:59
  • @bjtitus: Modifying the generated file was only the second-best solution (the "old answer"). And yes, you can wrap a type into an optional. A similar workaround is documented in https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc6_release_notes.html : *"If you encounter a method, property, or initializer for which the return value is incorrectly considered non-nullable, you can work around the problem by wrapping the result in an optional:"* – Martin R Dec 10 '14 at 23:01
  • so just something like `var foo = Optional(object.metadata)` – Ian Dec 10 '14 at 23:02
  • @MartinR That workaround will be fine for return types but if he is trying to cast a property to an optional and it is nil, it will crash, which is exactly what he is seeing. – bjtitus Dec 10 '14 at 23:21
  • @user3781236 Check my update and see if that is a suitable solution – bjtitus Dec 10 '14 at 23:31