Tuesday, January 25, 2022 [Tweets] [Favorites]

Clash of the Optionals

Tom Harrington:

What is an “optional” anyway? It depends who you ask. Swift will give you one answer, but Core Data has other ideas. So what happens when you bring them together?


Guess what, you just broke Swift’s initializer rules! Specifically, you initialized an object but didn’t provide a values for all of its non-optional properties. Nobody stopped you because @NSManaged says the rules don’t apply. You’ve just built a bomb.


Swift knows that initialization finished and there’s a non-optional property. It’s impossible for non-optional properties to be nil at this point, according to Swift. You can’t even check for nil values, that’s how definite this is. So it’s… not nil?


There is a way to check for nil first, but you have to pretty much forget that you’re using Swift first and fall back on key-value coding.

Making all your Core Data properties optional in Swift complicates the bulk of your code unnecessarily. But making them non-optional creates other problems, as above. I’ve also run into trouble with bridging changing nil to NSNull, which Core Data doesn’t like as a property value.


Update (2022-01-31): Jesse Squires:

Now we can write a designated initializer that provides default values where possible.


Simply remembering or telling our team to use only a specific initializer is prone to error. Luckily, we can prevent them from being called by marking them as unavailable. This will not only produce a compiler error if used, but it will also prevent them from appearing in Xcode’s auto-complete.

Note that this only affects what happens at compile time when dealing with this class. Core Data itself can still call other initializers on your behalf, e.g. during migration. You can still call the unavailable initializer when writing generic (not in the Swift generics sense) code to process managed objects, e.g. creating them based on an entity name and looking up their properties at runtime.

With sufficient test coverage for each model in Core Data, we can be confident that we will catch most errors that might result from modifying our models later on.


In case it isn’t obvious, all of this means you should not let Xcode automatically generate your managed object subclass definitions.


Finally, there is a risk of running into issues with faulting.

See also: Twitter.



Stay up-to-date by subscribing to the Comments RSS Feed for this post.

Leave a Comment