Swift core data: why do I need to unwrap when setting optional attribute values? - swift

I have a core data model that contains mainly optional attributes. I assumed then that I would not need to unwrap the values that I am assigning to these optional attributes. e.g. I thought I would be able to do:
myEntity.gravity = currentOrder.gravity
(myEntity.gravity being optional)
However, Swift still requires me to unwrap currentOrder.gravity. I would have thought given that the variable I am assigning to is optional that I would not need to unwrap this.
Update:
Here is the definition of one of the core data entities I am describing:
<attribute name="percentComplete" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
The entity itself:
<entity name="AircraftMeasurementsCD" representedClassName="AircraftMeasurementsCD" syncable="YES" codeGenerationType="class">

It seems you're equivocating on the word "optional".
The word "optional" in the attribute description optional="YES" is not the same as, and has nothing to do with, the Swift Optional enum type.
The former is merely the ordinary English word "optional", meaning "not required" — for a particular entity, there might or might not be a value for this attribute, which is a Float, but even if there isn't, it's a valid entity. Nothing in the story says that this attribute's type is Optional<Float>. Its type is Float. And you can't assign a Swift Optional where its wrapped type is expected; you have to unwrap it.
Indeed, this point is made very explicitly by the documentation:
Optional attributes aren’t required to have a value when saved to the persistent store. Attributes are optional by default.
Core Data optionals aren’t the same as Swift optionals. [My italics.]

Related

What is the point of using an "Implicitly Unwrapped Optional" as a function parameter type?

I go over some code written by other developers and now and then I encounter signatures like this one:
func didReceiveLogMessage(_ message: String!)
Would it be safe to convert this parameter type to String instead of String! ?
Basically never declare a custom function parameter as implicit unwrapped optional. Don't.
This is a pre Swift 3 legacy syntax only for Objective-C and Core Foundation compatibility.
It's absolutely safe and even highly recommended to remove the exclamation mark. However if you really need an optional use a regular optional (?)
This gives no value. It actually adds complexity as even an Inmplicitly unwrapped optional as such counts as an optional, meaning it can be nil (but will crash). a regular String can't be nil

How to get the underlying Value from a Swift KeyPath when its type is KeyPath<Root, Value!>?

Take a look at the following code:
struct Something {
var s: String! // Implicitly Unwrapped Optional
}
func bind<T, V>(keyPath: WritableKeyPath<T, V?>) {
}
bind(\Something.s)
The code above does not compile. If we change the signature of bind to bind<T, V>(keyPath: WritableKeyPath<T, V>) then it does compile, but the problem is that the type of V is String! and I need to get the underlying type, in this case String.
We can solve the problem as follows:
func bind<T, V>(keypath: WritableKeyPath<T, ImplicitlyUnwrappedOptional<V>>) {
}
Unfortunately the documentation says that ImplicitlyUnwrappedOptional is deprecated. However, it is not marked as deprecated with the #available attribute.
I'm hesitant to use a type that the docs say are deprecated, but I can find no other way to accomplish what I need.
Is there another way to get the implicitly wrapped generic Value type from a WritableKeyPath when its type is WritableKeyPath<T, V!>?
Will ImplicitlyUnwrappedOptional be removed at some point?
Is there another way to get the implicitly wrapped generic Value type from a WritableKeyPath when its type is WritableKeyPath<T, V!>?
Not that I'm aware of. Really the problem here is that \Something.s shouldn't be a WritableKeyPath<T, V!>. That should be illegal under the rules set out by SE-0054 (IUOs are attributes on declarations; they're not actual types that can satisfy generic placeholders).
Instead, \Something.s should be a WritableKeyPath<T, V?>, so really your original code ought to compile. This issue has been filed as a bug here.
Will ImplicitlyUnwrappedOptional be removed at some point?
Yes, this is set out by SE-0054:
Because IUOs are an attribute on declarations rather than on types, the ImplicitlyUnwrappedOptional type, as well as the long form ImplicitlyUnwrappedOptional<T> syntax, is removed. Types with nested IUOs are no longer allowed. This includes types such as [Int!] and (Int!, Int!).
However the type-checker implementation for this wasn't fully implemented for Swift 4, which is why you're still able to use ImplicitlyUnwrappedOptional as a type in order to work around your problem. It has been implemented for Swift 5 though, so your workaround will no longer compile on its release.
Although hopefully the IUO key path bug will have been fixed by then.

Is conditional binding in swift pass by value or reference?

I've been having some issues with conditional binding returning an invalid (but non-nil) object from the watch accelerometer. I was thinking maybe making a copy of the object could help the problem, but I wasn't sure if that was already occurring. If I use code such as:
if let data = recorder.accelerometerData(from: startDate, to: endDate){...}
is this already creating a copy of the CMSensorDataList object or am I simply getting a reference to it?
It just depends upon whether the type wrapped by the optional was a value type or reference type. If reference type, it's obviously pass by reference. If value type, it's copied (unless CoW, copy-on-write, in which case it's copied if and when it's mutated).
In this case, CMSensorDataList is a class, so it's a reference to that instance, not a copy of it.

Do #NSManaged variables have to be optional? [duplicate]

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.

In Swift, what does the ! symbol mean in a function signature?

In a Swift function signature, what does the ! after an argument imply? More specifically, does it mean the argument needs to be unwrapped before it is passed in or that it gets unwrapped (automatically) as it is passed in. Here is an example:
func annotationButtonTUI(sender: UIButton!) { }
In this case the function is a target for a UIButton so whatever happens with the ! is happening automatically.
My thought is it means you can expect an unwrapped sender object so you don't need to try an unwrap it.
This isn't quite a duplicate — there's some subtlety to implicitly unwrapped optionals in function signatures beyond their usage elsewhere.
You see implicitly unwrapped optionals in API imported from ObjC because that's the closest Swift approximation of an object that's expected to be there but which can be nil. It's a compromise for imported API — you can address these variables directly like in ObjC, and you can test them for nil using Swift optional syntax. (There's more about Apple's rationale for this in the Advanced Interoperability talk from WWDC14.) This pattern also applies to the IBAction declarations inserted by Interface Builder, since those methods are in effect getting called from ObjC code, too.
As you seem to have suspected, Swift wraps the possible nil in an optional when bridging from ObjC, but the ! in your function implementation's declaration unwraps the value so you can use it directly. (At your own risk.)
Since Swift 1.2 (Xcode 6.2 in Spring 2015), ObjC APIs can be annotated with nonnull and nullable, in which case the Swift interface to those APIs uses either a non-optional type or a fully optional type. (And since Swift 2.0 / Xcode 7.0, nearly all of Apple's APIs are audited to use nullability annotations, so their Swift signatures don't use much ! anymore.)
What's less well-known about this is that you're free to change the optionality of parameters when you implement your own Swift functions that get called by ObjC. If you want the compiler to enforce that sender in your action method can never be nil, you can take the ! off the parameter type. If you want the compiler to make sure you always test the parameter, change the ! to a ?.
The exclamation point after type declaration in the Swift method signatures means the parameter is an Implicitly Unwrapped Optional. That means it is an Optional type (that would be normally denoted with ? after the type) that gets unwrapped every time you access it in the method body. Not as it is passed in. It is as if you used forced unwrapping — sender!.titleLabel — each time you use it, but you do not have to type the exclamation point every time — hence implicitly unwrapped optional.
From Using Swift with Cocoa and Objective-C, section Working with nil:
Because Objective-C does not make any guarantees that an object is non-nil, Swift makes all classes in argument types and return types optional in imported Objective-C APIs. Before you use an Objective-C object, you should check to ensure that it is not missing.
Implicitly unwrapped optional allows you to treat it in the Swift code like a normal value type with the caveat that accessing it when it is nil will interrupt your program with runtime error. You’d guard against that using if statements, optional binding
or optional chaining.
Implicitly unwrapped optionals are pragmatic compromise to make the work in hybrid environment that has to interoperate with existing Cocoa frameworks and their conventions more pleasant, while also allowing for stepwise migration into safer programing paradigm — without null pointers — enforced by the Swift compiler. You’ll meet them all over Cocoa APIs, but there are also some use cases for them in pure Swift as discussed in Why create "Implicitly Unwrapped Optionals"?