How to Avoid Force Unwrapping a Variable

How to avoid force unwrapping a variable?

Use the if let or guard constructs:

func fullName() -> String {
if let middleName = middleName {
return "\(firstName) \(middleName) \(lastName)"

} else {
return "\(firstName) \(lastName)"
}
}

func fullName() -> String {
guard let middleName = middleName else {
return "\(firstName) \(lastName)"
}
return "\(firstName) \(middleName) \(lastName)"
}

I've put the guard statement in for completeness but as others have commented this is more commonly used in an error/failure case.

I would also advise against using string interpolation for Strings. They are already strings, there is no need to use the description of each name in a new string.

Consider return firstName + " " + lastName. See Difference between String interpolation and String initializer in Swift for cases when string interpolation could return an unexpected result.

How force unwrapping works in function parameters in Swift?

Here ! means the param will hold String value or nil. So when you assign nil to ! it is not supposed to crash.
But when you try to access that value, it will crash.

This modification in your code will cause a crash as we are trying to access the value inside the variable which is nil.

func getValue(param: String!) -> String {
if param.isEmpty {
return ""
}
return ""
}

let retVal = getValue(param: nil)

Another example:

var string: String!
string = nil //This will not crash, but after this line if you try to access or perform any operation on it, it will

Now about thisfunc getValue(param: String?) :

In this scenario the the param will be optional type unlike in the above scenario. So here you will have to unwrap it.

avoid force unwrapping inside a filter closure in Swift 4

You can avoid force unwrapping by directly comparing to true:

let tempFilteredResult = keysForAutoComplete.filter { $0?.contains("abc") == true }

or by using the nil coalescing operator ?? to unwrap the result:

let tempFilteredResult = keysForAutoComplete.filter { $0?.contains("abc") ?? false }

or by using the nil coalescing operator ?? to unwrap the input:

let tempFilteredResult = keysForAutoComplete.filter { ($0 ?? "").contains("abc") }

Explanation:

$0?.contains("abc") is using optional chaining and the result is a Bool? which is nil if the element is nil or Optional(true) or Optional(false) depending on whether the String contains "abc". You can compare a Bool? to a Bool, so comparing to true will return true only when there is a String that contains "abc".

The nil coalescing operator unwraps the value if it is not nil, or replaces it with the supplied default value if it is nil. Since you want a nil item to return false for the comparison, the way to safely unwrap is to use ?? false.

In the third example, the nil coalescing operator unwraps the value from tempFilteredResult replacing it with the empty string "" if it is nil.


If you'd like the result to be [String], you can use compactMap along with the trinary operator ?: to generate an array of [String]:

let tempFilteredResult = keysForAutoComplete.compactMap { $0?.contains("abc") == true ? $0 : nil }

Explanation:

Here, ?: is used to return the original value if it contains "abc" or nil if it does not. compactMap then eliminates the nil values and unwraps the String? to return a [String].

avoid force unwrapping inside a sort closure in Swift

You are sorting in descending order.

Use the nil coalescing operator ?? to safely unwrap the values and replace nil with Int.min to place the items at the end of the array:

// sorting each language array based on most stars
groupedDictionariesValueUnwrapped.sort(by: { ($0.stars ?? Int.min) > ($1.stars ?? Int.min) })

or use ?? Int.max to put them at the beginning.

Why using implicit unwrap or force unwrap letting the app crash at some stage not beneficial?

Sure. There any many proper uses of force-unwrapping where a crash will only occur early in development because a mistake has been made and once fixed, the crash won't ever happen again.

A common example is accessing an image from the resource bundle. A line such as:

let imagePath = Bundle.main.path(forResource: "image", ofType: "png")!

should crash in early development if the developer forgot to target image.png properly. Once targeted properly, that line won't crash so there's no reason to deal with an optional path.

Other common examples are outlets. They are usually made implicitly unwrapped because by the time they are used in the view controller's code, they will have been attached. A crash probably means the outlet wasn't connected properly. It gets fixed and there's no more worry. No need to deal with guards or other optional checking.

Last example (there are many more possibilities). When dequeuing a cell from a table view, force-cast the resulting cell to the custom cell type. No need for a guard. I see code here all the time that uses a guard with as? to throw a fatal error if the cast fails. Just force-cast. You get the same crash with less code. Once the table view and storyboard are correct, the force-cast won't fail.

Having said this, newer Swift developers should avoid the ! character on their keyboard for a while. Knowing when to safely use it is a learned skill.

If the potential crash is fully in the control of the developer and the crash could only happen because the developer make a mistake, then using ! may be appropriate.

If the potential crash can be caused by unexpected data (JSON parsing, user input, etc.), then never use !. Code defensively in those cases.

tl;dr - yes, there are plenty of cases where forced-unwraps, forced-casts, and implicitly unwrapped variables are the correct choice.

Swift: implicitly unwrapped variable works but not force cast it to the same type. Why?

Implicitly unwrapped optionals are actually (unsurprisingly), under the hood, optionals! The only advantage IUO's bring is the fact that you don't need to write the ! (forced unwrap) operator, the compiler does this for you.

Which means that nil values are acceptable values for IUO's. Which is why MyCell.createFromNib() is allowed to be assigned to myCell, even if the function might return nil under some conditions.

On the other hand MyCell.createFromNib() as! MyCell is evaluated before the assignment, and as! always results in a non-optional value, unless applied to a value that can't be cast (nil or another hierarchy). Thus, it's not the assignment that fails, it's the forced cast operation that triggers the fatal error.

MyCell.createFromNib() as? MyCell would've worked just as well, with the difference that instead of crashing this could've introduced a silent bug. Now, it's up to you to decide if this is preferable or not. I would've gone the semi-crash solution: a crash of Debug, a silent fail on Release. This way potential issues could be caught during the QA phase, however, if not caught they would not crash the production app.

let cell = MyCell.createFromNib()
assert(cell != nil, "Oops, something bad happened, please call the Avengers")
myCell = cell as? MyCell

Is it safe to force unwrap variables that have been optionally accessed in the same line of code?

Optional Chaining
from "The Swift Programming Language"
gives the following example:

 let john = Person()
// ...
let someAddress = Address()
// ...
john.residence?.address = someAddress

followed by (emphasis added):

In this example, the attempt to set the address property of john.residence will fail, because john.residence is currently nil.

The assignment is part of the optional chaining, which means none of the code on the right hand side of the = operator is evaluated.

Applied to your case: In

self?.variable = self!.otherVariable

the right-hand side is not evaluated if self is nil.
Therefore the answer to your question

If self indeed is nil, the second part will never happen?

is "yes". With regard to the second question

And it will never happen that self could be 'nilled' during this single line of code?

My original assumption was that once self has been determined to be != nil,
a strong reference to self! is held throughout the evaluation of the
statement, so that this can not happen. However (as @Hamish pointed out),
this is not guaranteed. Apple engineer Joe Groff writes at Confirming order of operations in
the Swift forum:

This isn't guaranteed. Releases may be optimized to happen earlier than this, to any point after the last formal use of the strong reference. Since the strong reference loaded in order to evaluate the left-hand side weakProperty?.variable is not used afterward, there is nothing keeping it alive, so it could be immediately released.

If there are any side effects in the getter for variable that cause the object referenced by weakProperty to be deallocated, nil-ing out the weak reference, then that would cause the force-unwrap on the right side to fail.
You should use if let to test the weak reference, and reference the strong reference bound by the if let

How to safely unwrap optional variables in dart?

Your Dart example seems incomplete but it is difficult to say what is wrong without more context. If myString is a local variabel it will be promoted. You can see this example:

void main(){
myMethod(null); // NULL VALUE
myMethod('Some text'); // Non-null value: Some text
}

void myMethod(String? string) {
if (string != null) {
printWithoutNull(string);
} else {
print('NULL VALUE');
}
}

// Method which does not allow null as input
void printWithoutNull(String string) => print('Non-null value: $string');

It is a different story if we are talking about class variables. You can see more about that problem here: Dart null safety doesn't work with class fields

A solution to that problem is to copy the class variable into a local variable in your method and then promote the local variable with a null check.

In general, I will recommend reading the articles on the official Dart website about null safety: https://dart.dev/null-safety



Related Topics



Leave a reply



Submit