Single line if statement in Swift - ios

How would one convert the following to Swift from Objective-C?
if (myVar) return;
Swift does not use parentheses around the conditional, however the following code gives an error.
if myVar return

Well as the other guys also explained that braces are a must in swift. But for simplicity one can always do something like:
let a = -5
// if the condition is true then doThis() gets called else doThat() gets called
a >= 0 ? doThis(): doThat()
func doThis() {
println("Do This")
}
func doThat() {
println("Do That")
}

In Swift the braces aren't optional like they were in Objective-C (C). The parens on the other hand are optional. Examples:
Valid Swift:
if someCondition {
// stuff
}
if (someCondition) {
// stuff
}
Invalid Swift:
if someCondition
// one liner
if (someCondition)
// one liner
This design decision eliminates an entire class of bugs that can come from improperly using an if statement without braces like the following case, where it might not always be clear that something's value will be changed conditionally, but somethingElse's value will change every time.
Bool something = true
Bool somethingElse = true
if (anUnrelatedCondition)
something = false
somethingElse = false
print something // outputs true
print somethingElse // outputs false

You can use new Nil-Coalescing Operator, since Swift 3 in case when you need just set default value in case of if fails:
let someValue = someOptional ?? ""
In case if someOptional is false, this operator assign "" to someValue
var dataDesc = (value == 7) ? "equal to 7" : "not equal to 7"

One-line if, one-line while and one-line for are considered a bad style by many developers because they are less readable and allegedly a source of many errors.
Swift solved the conundrum by forbidding one-line flow control statements; the braces are non-optional...
if someCondition {
// stuff
}
Of course, you can still do
if someCondition { return }
There are also implementation reasons. Having the parentheses around the condition as optional makes the parsing much harder. Enforcing braces simplifies parsing again.

Here is a simple solution I used in my projects.
Swift 4+
isManageCardTnCSelected ?
(checkbox.isSelected = true) : (checkbox.isSelected = false)
var selected: Bool = isManageCardTnCSelected ?
checkbox.isSelected = true : checkbox.isSelected = false
Swift 3+
var retunString = (state == "OFF") ? "securityOn" : "securityOff"

One line solution for Swift 3+
isMyVar ? someAction() : ()

Swift 5 Easy One line Solution
var isSeller = (UserDefaults.standard.value(forKey: "isRole") as? String == "ROLE_SELLER") ? true : false

Swift 5 Easy Solution
let exercise = (segcExercise.selectedSegmentIndex == 0) ? "GymLover" : (segcExercise.selectedSegmentIndex == 1) ? "Occasionally" : "No Way"
//MARK:- outPut // Occasionally

Related

If condition issues in swift

I know its a basic question but I'm facing an issue related to it that i'm getting data from backend service.
From service I got [] in response. and I'm comparing it with my model class array. Mean if my model class array is qual to [], than I have to perform something.
My code is this,
let addonCategory = subCategoryModel![tappedIndex.section].items[tappedIndex.row].addonCategory
print(addonCategory as Any)
if addonCategory == "[]"{
print("Hello")
}
else {
print("Hi")
}
But when i compare it with [] brackets it shows error message that,
Cannot assign value of type 'String' to type '[AddonCategoryModel]?'
How can i compare it with brackets?
You need to check whether an array has an element or not.
if addonCategory.count > 0 {
// array has element
} else {
// array hasn't element
}
Alternatively you can use guard let or if let to check.
Using if let
if let addonCategory = subCategoryModel[tappedIndex.section].items[tappedIndex.row].addonCategory, addonCategory.isEmpty {
print(addonCategory)
print("Hello")
} else {
print("Hi")
}
You have to use array properties on addonCategory. It is not of type String
let addonCategory = subCategoryModel![tappedIndex.section].items[tappedIndex.row].addonCategory
print(addonCategory.count == 0 ? "Hello" : "Hi")
Here I have used ternary operator instead of traditional if-else syntax.

if else shorthand crashes on setting bool in swift

I literally have 4 line of code.
var bool = true
let textField1 = UITextField()
let textField2 = UITextField()
bool ? textField1.enabled = false : textField2.enabled = false
The above code fails with following error.
if I write the following way the code works
if bool {
textField1.enabled = false
}
else {
textfield2.enabled = false
}
If I write the following way then short hand of if else works
bool ? print("It's True") : print("It's False")
Why is my code failing?
The reason is that Swift is not expecting you to behave like this. Thus, it sees the second term in the ternary as textField2.enabled, which is a Bool. But the first term, textField1.enabled = false, is not a Bool; it is a Void.
(That is why your print example works; both terms are Voids.)
As i_am_jorf says, you can work around this by disambiguating with parentheses.
However, it would be better not to do this at all. Your code is not very Swifty. You should not be using the ternary operator for side effects in this way. You should be using it for the result of each of its terms. This is much cleaner and even shorter:
(bool ? textField1 : textField2).enabled = false
Try this:
bool ? (textField1.enabled = false) : (textField2.enabled = false)
Note that the ternary operator is not an "if-else shorthand". It is defined as:
The ternary conditional operator evaluates to one of two given values based on the value of a condition. It has the following form:
condition ? expression used if true : expression used if false
If the condition evaluates to true, the conditional operator evaluates the first expression and returns its value. Otherwise, it evaluates the second expression and returns its value. The unused expression is not evaluated.
It's purpose is to assign a value based on a condition, not to allow flow control.

why I have to unwrap value before I use

A block is defined like below
// Declare block ( optional )
typealias sorting = (([Schedule], [String]) -> [Schedule])?
var sortSchedule: sorting = { (schedules, sortDescription) in
var array = [Schedule]()
for string in sortDescription
{
for (index, schedule) in schedules.enumerate()
{
if string == schedule.startTime
{
array.append(schedule)
break
}
}
}
return array
}
At some points, I am invoking a block by doing
let allSchedules = sortSchedule?(result, sortDescription())
for schedule in allSchedules // Xcode complains at here
{
..........
}
Im using ? because I want to make sure that if the block exists, then do something. However, Xcode complains for the for loop
value of optional type [Schedule]? not upwrapped, did you mean to use '!' or '?'?
Im not sure why because the return type of a block is an array which can have 0 or more than one items.
Does anyone know why xcode is complaining.
You are use ? in line let allSchedules = sortSchedule?(result, sortDescription()) not "for sure that if the block exists", but just for note, that you understand that it can be nil. Behind scene allSchedules have type Array<Schedule>?. And you can not use for in cycle for nil. You better use optional binding:
if let allSchedules = sortSchedule?(result, sortDescription())
{
for schedule in allSchedules
{
//..........
}
}

How to prettify enum with arguments comparison in Swift?

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 {
// ...
}

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