How to prettify enum with arguments comparison in Swift? - ios

This is what I have
let kind = //This returns one of the cases with it corresponding arguments
if kind == .didChangeValue(value: nil) {
//my Stuff
}
this is what I want:
if kind == .didChangeValue {
//my Stuff
}
Notice that:
This is happening because my enum has arguments, I already implemented how they should compare with each other and the value has no value to me.
So, I'm trying to get it to look more swifty and less like a RAW HACK

You can check an enumeration value with pattern matching:
if case .didChangeValue = kind {
// ...
}

Related

boolean return help to find fix

i have simple problem I want to return this one:
let results = prices.filter{
if($0.MultipleSearchString != nil){
predicate.evaluate(with: ($0.MultipleSearchString?.lowercased())!)
}else {
self.loadPricesFromDb()
}
}
but I have problem with it, because it giving problem like:
Missing return in a closure expected to return 'Bool' and I dunno why
Can someone explain me this?
You're using the filter function wrong.
Filter with an inline closure will evaluate each member of the array with the logic in the provided closure, and return an array of elements that satisfy that logic, e.g.:
let results = prices.filter {
$0.MultipleSearchString != nil
}
The above will have results with all elements that have MultipleSearchString different from nil.
It's also bad to call a function that presumably loads the data from database since it will trigger on (almost) every iteration.
You need to refactor your code to better work with your intended solution.

Printing value of $0

I have a certain line of code which looks like so...
let myMessages = theObjects.filter { $0.myJid.user == user.JID.user }
Now I want to print the value of $0.myJid.user. How can I achieve that..?
Another option:
let myMessages = theObjects.filter { print($0.myJid.user); return $0.myJid.user == user.JID.user }
You can do it like this.
let myMessages = theObjects.filter { (value) -> Bool in
print(value.myJid)
return value.myJid.user == user.JID.user
}
Tip: Naming your variable user seems like a bad idea since you already have a parameter with the same name for JID.
Edit: Seems i was wrong about not being able to print $0. You can do that just like in the regular closure. The only difference being you can omit the argument list and you need to add a return. To print using shorthand argument, check #Sateesh's answer.

How to avoid If let in Swift before doing a for loop

I have this code on Swift:
let items = doSomethingFuncToGetDataWithOptionalResults()
if let items = items {
for item in items {
// so something...
}
}
Could anyone can help me to avoid if let ... in this case. It would be better if we could ignore if let in this case. I feel annoyed when writing this statements every time.
Regards,
Generally, if a function returns an optional then you can use
optional chaining to operate on the result only if it is not nil.
In your case of an optional array you can use
optional chaining and forEach():
doSomethingFuncToGetDataWithOptionalResults()?.forEach { item in
// do something with `item` ...
}
The forEach() statement will not be executed if the function
returns nil.
You can do something like this:
if let items = doSomethingFuncToGetDataWithOptionalResults() {
for item in items {
// so something...
}
}

Assigning an enumerator and it's reverse to a variable

I'm stuck with this problem... I would like to enumerate in a regular for loop for one condition, and in reverse for another condition. Something like this:
var enumerator = 0..<length
if(stringPosition == .End) {
enumerator = reverse(enumerator) //[C.Generator.Element] is not convertible to 'Range<Int>'
}
for index in enumerator {
//do stuff
}
I'm getting a not convertible error there, and can't figure out how to proceed with that. I've tried different typecasting magic but that just doesn't work.
How should I sort out the conversion there?
Just casting to Array should work.
var enumerator = Array(0..<length) // <-- here
if(stringPosition == .End) {
enumerator = reverse(enumerator)
// then, enumerator.reverse() is better, I think
}
for index in enumerator {
//do stuff
}
I think, more (memory) efficient way is like:
let range = lazy(0..<length)
let enumerator = stringPosition == .End ? SequenceOf(range.reverse()) : SequenceOf(range)
for index in enumerator {
//do stuff
}
SequenceOf is a wrapper of any SequenceType. You can use this to store different sequence type to one variable.
for lazy(), see this answer or this.

Swift: Testing optionals for nil

I'm using Xcode 6 Beta 4. I have this weird situation where I cannot figure out how to appropriately test for optionals.
If I have an optional xyz, is the correct way to test:
if (xyz) // Do something
or
if (xyz != nil) // Do something
The documents say to do it the first way, but I've found that sometimes, the second way is required, and doesn't generate a compiler error, but other times, the second way generates a compiler error.
My specific example is using the GData XML parser bridged to swift:
let xml = GDataXMLDocument(
XMLString: responseBody,
options: 0,
error: &xmlError);
if (xmlError != nil)
Here, if I just did:
if xmlError
it would always return true. However, if I do:
if (xmlError != nil)
then it works (as how it works in Objective-C).
Is there something with the GData XML and the way it treats optionals that I am missing?
In Xcode Beta 5, they no longer let you do:
var xyz : NSString?
if xyz {
// Do something using `xyz`.
}
This produces an error:
does not conform to protocol 'BooleanType.Protocol'
You have to use one of these forms:
if xyz != nil {
// Do something using `xyz`.
}
if let xy = xyz {
// Do something using `xy`.
}
To add to the other answers, instead of assigning to a differently named variable inside of an if condition:
var a: Int? = 5
if let b = a {
// do something
}
you can reuse the same variable name like this:
var a: Int? = 5
if let a = a {
// do something
}
This might help you avoid running out of creative variable names...
This takes advantage of variable shadowing that is supported in Swift.
Swift 3.0, 4.0
There are mainly two ways of checking optional for nil. Here are examples with comparison between them
1. if let
if let is the most basic way to check optional for nil. Other conditions can be appended to this nil check, separated by comma. The variable must not be nil to move for the next condition. If only nil check is required, remove extra conditions in the following code.
Other than that, if x is not nil, the if closure will be executed and x_val will be available inside. Otherwise the else closure is triggered.
if let x_val = x, x_val > 5 {
//x_val available on this scope
} else {
}
2. guard let
guard let can do similar things. It's main purpose is to make it logically more reasonable. It's like saying Make sure the variable is not nil, otherwise stop the function. guard let can also do extra condition checking as if let.
The differences are that the unwrapped value will be available on same scope as guard let, as shown in the comment below. This also leads to the point that in else closure, the program has to exit the current scope, by return, break, etc.
guard let x_val = x, x_val > 5 else {
return
}
//x_val available on this scope
One of the most direct ways to use optionals is the following:
Assuming xyz is of optional type, like Int? for example.
if let possXYZ = xyz {
// do something with possXYZ (the unwrapped value of xyz)
} else {
// do something now that we know xyz is .None
}
This way you can both test if xyz contains a value and if so, immediately work with that value.
With regards to your compiler error, the type UInt8 is not optional (note no '?') and therefore cannot be converted to nil. Make sure the variable you're working with is an optional before you treat it like one.
From swift programming guide
If Statements and Forced Unwrapping
You can use an if statement to find out whether an optional contains a
value. If an optional does have a value, it evaluates to true; if it
has no value at all, it evaluates to false.
So the best way to do this is
// swift > 3
if xyz != nil {}
and if you are using the xyz in if statement.Than you can unwrap xyz in if statement in constant variable .So you do not need to unwrap every place in if statement where xyz is used.
if let yourConstant = xyz {
//use youtConstant you do not need to unwrap `xyz`
}
This convention is suggested by apple and it will be followed by devlopers.
Although you must still either explicitly compare an optional with nil or use optional binding to additionally extract its value (i.e. optionals are not implicitly converted into Boolean values), it's worth noting that Swift 2 has added the guard statement to help avoid the pyramid of doom when working with multiple optional values.
In other words, your options now include explicitly checking for nil:
if xyz != nil {
// Do something with xyz
}
Optional binding:
if let xyz = xyz {
// Do something with xyz
// (Note that we can reuse the same variable name)
}
And guard statements:
guard let xyz = xyz else {
// Handle failure and then exit this code block
// e.g. by calling return, break, continue, or throw
return
}
// Do something with xyz, which is now guaranteed to be non-nil
Note how ordinary optional binding can lead to greater indentation when there is more than one optional value:
if let abc = abc {
if let xyz = xyz {
// Do something with abc and xyz
}
}
You can avoid this nesting with guard statements:
guard let abc = abc else {
// Handle failure and then exit this code block
return
}
guard let xyz = xyz else {
// Handle failure and then exit this code block
return
}
// Do something with abc and xyz
Swift 5 Protocol Extension
Here is an approach using protocol extension so that you can easily inline an optional nil check:
import Foundation
public extension Optional {
var isNil: Bool {
guard case Optional.none = self else {
return false
}
return true
}
var isSome: Bool {
return !self.isNil
}
}
Usage
var myValue: String?
if myValue.isNil {
// do something
}
if myValue.isSome {
// do something
}
One option that hasn't specifically been covered is using Swift's ignored value syntax:
if let _ = xyz {
// something that should only happen if xyz is not nil
}
I like this since checking for nil feels out of place in a modern language like Swift. I think the reason it feels out of place is that nil is basically a sentinel value. We've done away with sentinels pretty much everywhere else in modern programming so nil feels like it should go too.
Instead of if, ternary operator might come handy when you want to get a value based on whether something is nil:
func f(x: String?) -> String {
return x == nil ? "empty" : "non-empty"
}
Another approach besides using if or guard statements to do the optional binding is to extend Optional with:
extension Optional {
func ifValue(_ valueHandler: (Wrapped) -> Void) {
switch self {
case .some(let wrapped): valueHandler(wrapped)
default: break
}
}
}
ifValue receives a closure and calls it with the value as an argument when the optional is not nil. It is used this way:
var helloString: String? = "Hello, World!"
helloString.ifValue {
print($0) // prints "Hello, World!"
}
helloString = nil
helloString.ifValue {
print($0) // This code never runs
}
You should probably use an if or guard however as those are the most conventional (thus familiar) approaches used by Swift programmers.
Optional
Also you can use Nil-Coalescing Operator
The nil-coalescing operator (a ?? b) unwraps an optional a if it contains a value, or returns a default value b if a is nil. The expression a is always of an optional type. The expression b must match the type that is stored inside a.
let value = optionalValue ?? defaultValue
If optionalValue is nil, it automatically assigns value to defaultValue
Now you can do in swift the following thing which allows you to regain a little bit of the objective-c if nil else
if textfieldDate.text?.isEmpty ?? true {
}
var xyz : NSDictionary?
// case 1:
xyz = ["1":"one"]
// case 2: (empty dictionary)
xyz = NSDictionary()
// case 3: do nothing
if xyz { NSLog("xyz is not nil.") }
else { NSLog("xyz is nil.") }
This test worked as expected in all cases.
BTW, you do not need the brackets ().
If you have conditional and would like to unwrap and compare, how about taking advantage of the short-circuit evaluation of compound boolean expression as in
if xyz != nil && xyz! == "some non-nil value" {
}
Granted, this is not as readable as some of the other suggested posts, but gets the job done and somewhat succinct than the other suggested solutions.
If someone is also try to find to work with dictionaries and try to work with Optional(nil).
let example : [Int:Double?] = [2: 0.5]
let test = example[0]
You will end up with the type Double??.
To continue on your code, just use coalescing to get around it.
let example : [Int:Double?] = [2: 0.5]
let test = example[0] ?? nil
Now you just have Double?
This is totally logical, but I searched the wrong thing, maybe it helps someone else.
Since Swift 5.7:
if let xyz {
// Do something using `xyz` (`xyz` is not optional here)
} else {
// `xyz` was nil
}

Resources