Hello I have an optional variable which uses the willset functionality. Since its an optional the regular set will not work. inside the will set I am setting the variable to at least initialize it if the new value is nil. unfortunately, the value after is nil as well any ideas? Thank you
Code:
var arrayOfString: [String]? {
willSet {
self.arrayOfString = newValue == nil ? [String]() : newValue
}
}
Since its an optional the regular set will not work
Not correct. Since it's not a computed property set will not work.
You need to reread the section about willSet and didSet. willSet is called before any value is written to the variable. I.e. whatever you write to the variable inside willSet will be overwritten immediately by the assignment that invokes your code.
If you assign nil you will overwrite your string array with nil.
Simplify by just doing
var arrayOfString: [String] = []
You need to use didSet:
var arrayOfString: [String]? {
didSet {
self.arrayOfString = arrayOfString ?? []
}
}
Otherwise the value is immediately overwritten by the original value.
However note that if the variable should never contain an optional, it should be declared as such:
var arrayOfString: [String]
and the assignment should add the ?? [] when needed.
Otherwise you will have to handle unwrapping everytime you access the value anyway.
Related
I want to initialize my Empty Array with some data, however the array does not accept new data, It must be easy thing, but I do not know what I am missing!
var arrayOfString: [String]?
arrayOfString?.append( "New Data"); print( "\(arrayOfString?.count)" )
Initializing means to assign a default value
var arrayOfString: [String]? = []
But in almost all cases collection types can be declared (and initialized) non-optional
var arrayOfString = [String]()
Does it mean that the set operation doesn't read the actual value of the Optional, so it doesn't need to be unwrapped?
var str = "Hello, playground"
class Base{
var name:String?
};
var obj = Base()
obj.name = "hello" //this line don't need unwrapping first
An optional is a box. The box can either contain nothing (which is called nil) or it can contain something of a specific type (a String in your example). You unwrap an optional to access the value inside in the box.
When you are assigning a value to an optional, you just need to assign the value to the box itself. There is no need to unwrap anything, because you are just putting a value into the box. Swift either empties the box, if you assign nil, or it wraps the value by putting it into the box.
Unwrapping is for accessing a value that is already in the box.
Answering your question from a comment on another answer...
But why Optional binding don't need unwrapping? i think i if let constantName = some Optional is kind of assignment too
Optional binding is an unwrapping operation and an assignment operation. It says "if there is a value inside the box, assign it to this new variable and enter the then clause, otherwise proceed to the else clause if it exists".
var optionalValue: String? = "hello"
if let value = optionalValue {
// value is the contents of the box, it has type String
print("value is \(value)")
} else {
// the optional binding failed because the box is empty
print("optionalValue is nil")
}
When you set an Optional property, you do not have to unwrap it.
Unwrapping is required only when assigning an optional value to a non-optional property:
var name: String = "" // non-optional
var str: String?
// this will not compile, because you need to unwrap str first
name = str
// this will compile, because we're providing a default value
name = str ?? ""
// this will also compile, because name is not an optional
// it would still compile if name was optional, because str is optional too
str = name
I'm new to Swift and I'm wondering if there's a 'short hand' form of assigning Optional values to non-optional values without doing if nil check.
For example if I've got an Optional closure:
var onTap: (() -> Void)?
I can later on call this via
onTap?()
The ? let's me skip the nil check and force unwrap.
But I'm curious if something exists for values that are not clousre. For example
var oldTransform: CGAffineTransform?
var someTransform: CGAffineTransform //non optional
and later on, I decide to assign oldTransform to someTransform I have to
if (oldTransform != nil) {
someTransform = oldTransform!
}
Is there a pattern that's less verbose to do the above (kinda of like the ?)?
Yes, of course. You could use if let as below:
if let unwrappedOldTransForm = oldTransform {
someTransform = unwrappedOldTransForm
}
When you check with if let, it will unwrap the value for you and check if it can set the value of oldTransform to unwrappedOldTransForm. If the value is nil you will be able to handle the error by adding an else condition as below:
if let unwrappedOldTransForm = oldTransform {
someTransform = unwrappedOldTransForm
} else {
// handle if oldTransform is nil
}
In the case of a function, as you know, "calling" a nil function (like onTap?()) has no effect - but for an assignment to a non-optional type you need to supply a definite non-optional value. For that you can use the nil-coalescing operator ?? like so:
var optionalString: String?
// ... maybe set optionalString ...
var realString: String = optionalString ?? "<some default value>"
In your example, it would be
someTransform = oldTransform ?? CGAffineTransform(...) // some default - say Identity
or even, as commentator #user28434 suggests
someTransform = oldTransform ?? someTransform // assuming someTransform already initialised
which will only change someTranform if oldTransform isn't nil.
In each case, the left hand operand of ?? will be assigned if is non-nil, otherwise the right hand side operand will be assigned.
I want to know about Bool in Swift.
If Bool is a basic primitive datatype, why is a Boolean's default value nil?
var test: Bool!
print(test) // nil
In Java the Boolean default value is false:
Default value of 'boolean' and 'Boolean' in Java
Bool, Bool! and Bool? all are different in Swift.
1. Bool is a non-optional data type that can have values - true/false. You need to initialize it in the initializer or while declaring it before using it.
var x : Bool = false
var x: Bool
init()
{
x = false
}
2. Bool? is an optional data type that can have values - nil/true/false. In order to use this type, you need to unwrap it using if let or force unwrapping.
var x: Bool?
if let value = x
{
//TODO: use value instead of x
}
3. Bool! is an implicitly unwrapped optional data type that can have values - nil/true/false. The difference here is it must contain a value before using it else it will result in runtime exception. Since it is implicitly unwrapped, no need to unwrap it using if let or force unwrapping.
var x: Bool! //Must contain value before using
Strictly spoken there is no default value in Swift.
Either the Bool is non-optional then you have to assign a (default) value
or if the Bool is an optional, then it is nil – which is no value in terms of Swift.
Bool in Swift is not a primitive. Everything in Swift are objects. Your variable test is a Bool!, which is an implicitly unwrapped optional and the default value is nil.
If you use this code (not an optional),
var test: Bool
print(test)
You will get an error:
variable 'test' used before being initialized
So in Swift you have to initialize stuff before you use it, for example:
var test: Bool = false
I'm reading Apple's developer documentation on Optional Binding
Why can't I use:
if someOptional? {
statements
}
Instead of
if let constantName = someOptional {
statements
}
Why when there is no need for a local variable or constant?
Why can't I use: if someOptional? {...}
Because the ? suffix on an optional variable is reserved for optional chaining, which allows you to access a property or call a method on a given optional variable. For example:
// returns an optional version of a given property
let aProperty = anOptional?.someProperty
// calls the method if aProperty contains a value – otherwise doesn't
aProperty?.doSomething()
If you just want to check whether an optional contains a value, but don't care about that underlying value, you can simply compare it with nil. For example:
if anOptional != nil {
// do something
}
The simple answer is that someOptional is an Optional, whereas constantName is a Type.
An Optional is not simply the state of a variable, it's an entirely different type. If you were to set var someOptional: String? to var someOptional: String, you're not unwrapping someOptional, you're actually changing the type of someOptional.
It's functionally the same as changing var someOptional: String to var someOptional: Int