Do Optionals default to nil?
Yes it is automatically set to nil if unassigned.
From Apple:
If you define an optional variable without providing a default value,
the variable is automatically set to nil for you
Constant unassigned optional will not be nil by default
Yes it's correct
An optional variable doesn't need to be manually initialized. If you read it before having populated it does contain nil
.
From Apple docs
If you define an optional variable without providing a default value, the variable is automatically set to nil for you [...]
On the other hand the compiler does force you to manually initialize an Optional constant (let
) before you can read it.
Unlike a variable, the value of a constant cannot be changed once it is set. Attempting to do so is reported as an error when your code is compiled [...]
Why?
A constant can be written only once. It doesn't need to happened on the same line it is initialized but it must happened before your read it.
E.g. this code works fine
let num: Int?
num = 1
print(num)
However if the compiler had put a temporary nil
value inside num
then the constant would have been wrote twice. Which is against the concept of constant.
let num: Int?
print(num) // nil ??? <- this can't work!
num = 1
print(num) // 1
Another example
This code snippet works fine
func printArea(width: Int?, height:Int?) {
let area: Int?
if let width = width, height = height {
area = width * height
} else {
area = nil
}
print(area)
}
Again, if the compiler had put a temporary nil
value inside area
then...
func printArea(width: Int?, height:Int?) {
let area: Int?
print(area) // not possible! area is going to change in a moment
if let width = width, height = height {
area = width * height
} else {
area = nil
}
print(area)
}
Why optional constant does not automatically have a default value of nil
Not setting a read-only (constant) field with either an:
- initialization expression
- initializer
is almost certainly an indication of an error in your program.
Since you have no other opportunity to set the value of your let
field, the value of the field is going to remain nil
(or some other default). It is rather unlikely that a programmer would find such behavior desirable, and request it on purpose.
That is why Swift marks this situation as an error. On the other hand, if you actually wanted your String
constant to remain nil
, you could add an expression to set it to nil
, and silence the error:
let owner: String? = nil // Pretty useless, but allowed
How to disable default nil-initialization of Optional
If your var
's type is written T?
with no default value, and Swift synthesizes a memberwise init
for your type, then the synthesized init
uses a default value of nil
for that var
.
However, if your var
's type is written Optional<T>
with no default value, then the synthesized init
does not use a default value.
So write this instead:
struct DataOne {
let id: String
var name: Optional<String>
// ...
}
struct DataTwo {
let id: String
var name: Optional<String>
// ...
}
Or write out your init
instead of letting the compiler synthesize it:
struct DataOne {
let id: String
var name: String?
init(id: String, name: String?) {
self.id = id
self.name = name
}
}
struct DataTwo {
let id: String
var name: String?
init(id: String, name: String?) {
self.id = id
self.name = name
}
}
You can use Xcode's Editor > Refactor > Generate Memberwise Initializer command to write most of the init
for you, then delete the = nil
default:
No need for initializer for optional properties inside Swift class
Optional Property Types :
If your custom type has a stored property that is logically allowed to have “no value”—perhaps because its value cannot be set during initialization, or because it is allowed to have “no value” at some later point—declare the property with an optional type. Properties of optional type are automatically initialized with a value of nil, indicating that the property is deliberately intended to have “no value yet” during initialization.
For Example :
class SurveyQuestion {
var text: String?
init(text: String) {
self.text = text
}
func ask() {
print(text)
}
}
let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?")
cheeseQuestion.ask()
// Prints "Do you like cheese?"
let cheeseQuestion1 = SurveyQuestion()
cheeseQuestion.ask()
// Prints nil
When should I use optionals and when should I use non-optionals with default values?
The choice depends on what you model.
If a property of the object that you model may be absent completely, e.g. a middle name, a name suffix, an alternative phone number, etc., it should be modeled with an optional. A nil
optional tells you that the property is not there - i.e. a person does not have a middle name or an alternative phone number. You should also use optional when you must distinguish between an empty object and a missing object.
If a property of the object must be set, and has a meaningful default, use an non-optional with a default:
class AddressList {
var addresses : [Address]
var separator : String = ";"
...
}
If users of your class need to change the separator, they have a way to do that. However, if they do not care about the separator, they can continue using the default without mentioning it in their own code.
Providing a default value for an Optional in Swift?
Update
Apple has now added a coalescing operator:
var unwrappedValue = optionalValue ?? defaultValue
The ternary operator is your friend in this case
var unwrappedValue = optionalValue ? optionalValue! : defaultValue
You could also provide your own extension for the Optional enum:
extension Optional {
func or(defaultValue: T) -> T {
switch(self) {
case .None:
return defaultValue
case .Some(let value):
return value
}
}
}
Then you can just do:
optionalValue.or(defaultValue)
However, I recommend sticking to the ternary operator as other developers will understand that much more quickly without having to investigate the or
method
Note: I started a module to add common helpers like this or
on Optional
to swift.
nil in an optional type, what exactly is behind it? what it looks like in the memory?
With this
var john: Person?
A slot of memory is added on top of the Stack
.
The type of this slot is Optional
value of type Person
Optional<Person>
Inside this location of memory we found the Optional.none
value.
After this
john = Person(name: "Mr Robot")
some memory is allocated into the Heap
.
This memory is then written following the logic of the Person initializer
.
Then let's get back to the Stack.
Here the Optional.none
is replaced with the value Optional.some
and the address memory of the Person
object is written inside a special a field of the enum value.
Related Topics
Swiftui - Two Buttons in a List
How to Create Nsradiobutton Group in Xcode 7 Osx
Conditionally Use View in Swiftui
Adding a Case to an Existing Enum with a Protocol
Getting Optional("") When Trying to Get Value from Keychain
Swift Error: Binary Operator '&&' Cannot Be Applied to Two 'Bool' Operands
How to Print a String from Plist Without "Optional"
Swift 2 Migration Savecontext() in Appdelegate
Swiftier Swift for 'Add to Array, or Create If Not There...'
Converting Swift Array to Cfarray in Xcode 8 (Swift 3)
Ondelete Causing Nsrangeexception
How to Update Text Using Timer in Swiftui
Confusion Due to Swift Lacking Implicit Conversion of Cgfloat
Anonymous Closure Argument Not Contained in a Closure
Initializer for Conditional Binding Must Have Optional Type, Not 'String'