avoid force unwrapping inside a filter closure in Swift 4
avoid force unwrapping inside a filter closure in Swift 4
I am trying to filter array of [String?] with "abc".
// keysForAutoComplete: [String?]
let tempFilteredResult = keysForAutoComplete.filter ($0?.contains("abc"))!
How can I avoid force unwrapping within the closure ? I know about if let and guard let statements, but not quite sure how to apply them here?
keysForAutoComplete
@Carpsen90 optional string
– Ali_C
Aug 25 at 15:05
like ["abcd", "kjm", "babc", nil] ?
– Carpsen90
Aug 25 at 15:05
@Carpsen90 yes. vacawama's answer is what I was looking for.
– Ali_C
Aug 25 at 15:10
2 Answers
2
You can avoid force unwrapping by directly comparing to true
:
true
let tempFilteredResult = keysForAutoComplete.filter $0?.contains("abc") == true
or by using the nil coalescing operator ??
:
??
let tempFilteredResult = keysForAutoComplete.filter $0?.contains("abc") ?? false
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"
.
$0?.contains("abc")
Bool?
nil
nil
Optional(true)
Optional(false)
String
"abc"
Bool?
Bool
true
true
String
"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
.
nil
nil
nil
false
?? false
If you'd like the result to be [String]
, you can use compactMap
along with the trinary operator ?:
to generate an array of [String]
:
[String]
compactMap
?:
[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]
.
?:
"abc"
nil
compactMap
nil
String?
[String]
as the first syntax is more elegant and easier to follow, let say there a nil in the array and I use == true. What did you mean by saying ??false is safer? I tried using ==true on an array that had a nil value and it did not crash.
– Ali_C
Aug 25 at 15:53
Both are equally safe. The first isn't unwrapping the optional. It is comparing the optional to
true
to create a new Bool
. ?? false
unwraps the optional. Either work; use the one you like.– vacawama
Aug 25 at 15:56
true
Bool
?? false
You can use compactMap
operator to remove nil
values and left your array as [String]
type, so every element will be a non-optional value. After that, you can use filter
on the new array. This way, you don't need to be worried about nil values, then unwrapping is no needed.
compactMap
nil
[String]
filter
let keysForAutoComplete = ["abc", "ab", nil, "bca", "abcd"]
let tempFilteredResult = keysForAutoComplete.compactMap$0.filter$0.contains("abc")
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
What are the contents of
keysForAutoComplete
?– Carpsen90
Aug 25 at 14:57