Why does Realm use RealmOptional<Int> rather than Int? for optional properties? - swift

Realm's documentation on optional properties states:
String, NSDate, and NSData properties can be declared as optional or non-optional using the standard Swift syntax. Optional numeric types are declared using RealmOptional.
Why do numeric types use the non-standard RealmOptional rather than Swift's built-in optional syntax?

Realm model classes automatically implement getters and setters for your persisted properties that access the underlying database data. In order to provide these getters and setters, your properties must be declared with the dynamic modifier. This modifier asks Swift to dynamically dispatch accesses to the properties via getters and setters rather than directly accessing the member at compile time. The dynamic modifier comes with a significant limitation: it is only supported for types that can be represented in Objective-C. This is because Swift's dynamic dispatch is built on top of the Objective-C runtime. It is this limitation that prevents Int? from being directly supported by Realm.
You may wonder how String?, NSData?, and NSDate? are supported given this limitation. The answer is that they have natural equivalents in Objective-C, namely nullable NSString *, nullable NSData *, and nullable NSDate *. No such equivalents exist for Swift's numeric types.

Related

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

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

Swift protocols mutability [duplicate]

This question already has answers here:
Read-only properties of protocols in Swift
(3 answers)
Why am I allowed to set a read only property of a protocol using a struct that inherits said protocol?
(3 answers)
Closed 2 years ago.
I'm currently a bit confused about gettable properties in protocols. Consider this example:
protocol Person {
var name: String { get }
}
I expected the name property to be read-only, but I found that you could change the value without compiler complaints:
struct Driver: Person {
var name: String
}
var driver = Driver(name: "Ryan")
driver.name = "Changed!"
If we define driver with let keyword, then compiler raises the error, but if I understand correctly, it has nothing to do with protocols, as constant structs are immutable by design in Swift.
Method interactions behave as I would've expected:
extension Person {
mutating func changeName(_ newName: String) {
self.name = newName // Error: 'name' is a get-only property
}
}
I'm new to Swift, and the nuance mentioned may not have any practical use, but this behavior made me ask myself if I lack some basic understanding of how structs work.
The protocol requirement is
a variable name which can be read
which doesn't mean that the variable in a struct adopting this protocol is necessarily read-only.
In the code you are changing the variable directly in the Driver type, the protocol is not involved.
On the other hand if you annotate the protocol type you get the expected error
var driver : Person = Driver(name: "Ryan")
driver.name = "Changed!" // Cannot assign to property: 'name' is a get-only property
A protocol only declares the required interface, but not the full interface of conforming types. Your conforming types can add extra properties/methods that aren't required by the protocol.
The same is true for getters and setter. If a protocol property requirement is get, that means the conformant type must have a getter for the property, but doesn't mean it cannot have a setter for it as well.
However, the same doesn't work the other way around. If a protocol declares a property as { get set }, that property must have a setter (be mutable).
The apple documentation explains this very well.
The getter and setter requirements can be satisfied by a conforming type in a variety of ways. If a property declaration includes both the get and set keywords, a conforming type can implement it with a stored variable property or a computed property that is both readable and writeable (that is, one that implements both a getter and a setter). However, that property declaration can’t be implemented as a constant property or a read-only computed property. If a property declaration includes only the get keyword, it can be implemented as any kind of property.

What types cannot be cast to `AnyObject` in Swift 4?

I've experimented with casting many types to AnyObject. Reference types obviously cast unaltered, but others are automagically converted under the hood to NSNumber, NSValue, and so on. (These are not the exact types, but close enough.) I was even able to cast a tuple successfully.
This surprised me. Are there any types that cannot be cast to AnyObject?
There are other questions and answers that may cover this material, but none of them asks this question specifically and the answer to this question can only be found in the fine print of the other answers.
AnyObject is Objective-C id, meaning any class type. Casting to AnyObject means "wrap this up in a way that Objective-C can deal with as a class type."
Obviously, an NSObject subclass just crosses the bridge directly.
For other types (i.e. nonclasses), Swift 4 follows three policies:
Some types are bridged directly to classes, e.g. String to NSString.
Some types are wrapped in Objective-C class types, e.g. Int in NSNumber or CGRect in NSValue.
All other types are boxed in an opaque wrapper; they can cross the bridge to Objective-C, and can be round-tripped successfully back to Swift, but nothing useful can be done with them in the Objective-C world.

Realm: Swift `let` property cannot be marked as dynamic

I am using Xcode 7.2, Swift 2.1.1. I have a Realm model object below
class B: Object {
dynamic let lists = List<A>()
}
But the Swift compiler gives me an error saying:
Property cannot be marked as dynamic because its type cannot be represented in Objective-C
I saw Realm's documentation that says:
Realm model properties need the dynamic var attribute in order for these properties to become accessors for the underlying database data.
There are two exceptions to this: List and RealmOptional properties
cannot be declared as dynamic because generic properties cannot be
represented in the Objective-C runtime, which is used for dynamic
dispatch of dynamic properties, and should always be declared with let
But declaring let doesn't seem to solve this case now. What am I missing?
The documentation you quoted includes the following (emphasis mine):
List and RealmOptional properties cannot be declared as dynamic because generic properties cannot be represented in the Objective-C runtime, […], and should always be declared with let.
This means your property should be declared like so:
let lists = List<A>()
The Realm Swift documentation recently gained a property declaration cheatsheet which hopefully clarifies the requirements for the different types of declarations.

Class type properties should not have static keyword?

This is an image from Apple's documentation example, Why do the first 2 properties have the 'static' keyword?? I thought static should be only used for structures and enums?
Secondly, why does this class have a stored type property? I thought classes could only have computed type properties???
Effective Swift 1.2, static properties are now permitted in classes.
Classes have always been permitted to have stored properties.
From the Xcode 6.3 (Swift 1.2) release notes, under Swift Language Enhancements:
static methods and properties are now allowed in classes (as an
alias for class final).
You are now allowed to declare static stored properties in classes, which have global storage and are lazily
initialized on first access (like global variables).