Use if-let for more than one condition - swift

I have a code that looks like so:
let myItems = presenter?.getShoppingListItems()
if myFlag.isEnabled() && myItems!.isEmpty {
//Do something
Now, I want to write this line if myFlag.isEnabled() && shoppingListItems!.isEmpty using if-let.
I tried this:
let myItems = presenter?.getShoppingListItems()
if let _ = myFlag.isEnabled(), let myItems = myItems?.isEmpty {
//Do something
And this:
let myItems = presenter?.getShoppingListItems()
if let myFlag.isEnabled(), let _ = myItems?.isEmpty {
//Do something
But it's not working. What am I missing here?

Optional binding (if let ...) is supposed to be used when you want to unwrap an optional value and bind it to an identifier. Here, you are not trying to bind anything - you are just trying to check two conditions: myFlag.isEnabled() and myItems?.isEmpty, so a regular if condition will work.
You do need to make sure that the conditions are of type Bool though, not Bool?.
Assuming yo do not want the if statement to run when myItems is nil, you can achieve this by directly comparing the optional myItems?.isEmpty with true.
if myFlag.isEnabled() && myItems?.isEmpty == true {
Alternatively, you can mix optional binding with regular Bool conditions. You can bind myItems, and check isEnabled and isEmpty, all within the same if statement:
if let myItems = presenter?.getShoppingListItems(),
myFlag.isEnabled(), myItems.isEmpty == true {
}
Or you can bind on myItems?.isEmpty, since that is an optional as well:
if let isEmpty = myItems?.isEmpty,
myFlag.isEnabled(), isEmpty {
}
If you want the if statement to also be executed when myItems is nil, you can change the condition to != false:
if myFlag.isEnabled() && myItems?.isEmpty != false {

You can try
if let items = presenter?.getShoppingListItems(), items.isEmpty, myFlag.isEnabled() { ... }

Related

Swift : affect struct by reference or "alias" to a variable

I have to update a struct, but this struct needs a long expression to be found from my viewController :
let theMessage:Message? = self.messageSections.first(where: { $0.date == DateDMY(fromNSDate:msg.date) })?
.msgs.first(where: { $0 == msg })
I want to mutate one property of this struct, but not a copy of it, I want to update it "where it is", that is in messageSections[].msgs[]
The problem here is that if I try this code after the one above :
theMessage.status = .NOT_SENT
Only the local copy will be updated, and not the real one in messageSections[].msgs[]. So when I reload my collectionView, nothing changes.
I could do
self.messageSections.first(where: { $0.date == DateDMY(fromNSDate:msg.date) })?
.msgs.first(where: { $0 == msg }).status = .NOT_SENT
But if I have to manipulate this property several times in my function, I dont want to re-write the whole expression each time. So what I'm looking for is something like in C :
let theMessage:Message?* = &self.messageSections.first(where: { $0.date == DateDMY(fromNSDate:msg.date) })?
.msgs.first(where: { $0 == msg })
if(theMessage != NULL)
theMessage->status = .NOT_SENT
I saw in other questions that I could use & before argument and inout before parameter name, but its only for functions calling. I'm looking for a way to create an alias for a big expression when affecting a variable, just to avoid re-writting it each time.
You can use firstIndex to get the index of the element in the array, then access the element directly using the retrieved index.
if let messageSectionIndex = self.messageSections.first(where: { $0.date == DateDMY(fromNSDate:msg.date) }), let messageIndex = self.messageSections[messageSectionIndex].msgs.firstIndex(where: { $0 == msg }) {
self.messageSections[messageSectionIndex].msgs[messageIndex].status = .NOT_SENT
}

How to remove optional from a string value in swift?

In the code I'm not able to remove optional from the value inside the lbltotalamount.
The value in lblTotalAmount is not removing its optional value from it.
Why? The value in grandtotal gets optional removed but when I assign it to a label it returns an optional value again.
The lblTottalAmount is getting an optional value. I want to remove it.
if success == false {
var grandtotal: Any? = value["total"]
if grandtotal != nil {
print("O!O!O!O/\(grandtotal!)")
grandtotal = String(describing: grandtotal)
self.lblTotalAmount.text = ([grandtotal]) as! String // (here I am not able to remove optional)
}
The problem is in the line
grandtotal = String(describing: grandtotal)
You check for nil but you don't unwrap the value so it's still an optional.
And you are misusing String(describing. Never use it for types which can be converted to String with an init method.
Use always conditional downcast
if success == false {
if let grandtotal = value["total"] as? Double {
self.lblTotalAmount.text = String(grandtotal)
}
}

Setting variable equal to if statement condition

I have an if statement that checks to see if an array element matches a local variable.
if pinArray.contains(where: {$0.title == restaurantName})
How would I create a variable of this element?
I attempted
let thePin = pinArray.contains(where: {$0.title == restaurantName})
but this comes with "could not cast boolean to MKAnnotation".
I also tried variations of
let pins = [pinArray.indexPath.row]
let pinn = pins(where: pin.title == restaurantName) (or close to it)
mapp.selectAnnotation(thePin as! MKAnnotation, animated: true)
to no avail. What basic step am I missing?
contains(where:) returns a Bool indicating whether a match was found or not. It does not return the matched value.
So thePin is a Bool which you then attempt to force-cast to a MKAnnotation which of course crashes.
If you want the matching value, change your code to:
if let thePin = pinArray.first(where: { $0.title == restaurantName }) {
do {
mapp.selectionAnnotation(thePin, animated: true)
} catch {
}
} else {
// no match in the array
}
No need for contains at all. No need to cast (assuming pinArray is an array of MKAnnotation).

Is it possible to use the variable from an optional binding within the same conditional statement?

if let popupButton = result?.control as? NSPopUpButto {
if popupButton.numberOfItems <= 1 {
// blahblah
}
}
I want to avoid the double nested if.
if let popupButton = result?.control as? NSPopUpButton && popupButton.numberOfItems <= 1 {}
but I get the unresolved identifier compiler error if I do that.
Is there any way to make this condition on one line? Or because I'm using an optional binding, am I forced to make a nested if here?
You can do it this way:
if let popupButton = result?.control as? NSPopUpButton, popupButton.numberOfItems <= 1 {
//blahblah
}

Swift-y boolean expression - case outside if/switch

To continue to the next screen, a patron must have one of two identifiers. The code I've got to do this is:
let identifier1Entered = !patron.identifier1.isEmpty
let identifier2Entered = patron.identifier2 != nil && !patron.identifier2!.isEmpty
guard identifier1Entered || identifier2Entered else { return }
But it's not Swifty, I'm force-unwrapping the optional identifier2, because I don't want to expand this to a longer, and IMO messier
var identifier2Entered = false
if let identifier2 = patron.identifier2 where !identifier2.isEmpty {
identifier2Entered = true
}
What I thought might work is just taking the expression out of the if statement, like:
let id2Entered = let identifier2 = patron.identifier2 where !identifier2.isEmpty
or
let id2Entered = case .Some(let id2) = patron.identifier2 where !id2.isEmpty
But it appears that these expressions are only allowed within if statements.
The other more Swifty solution I thought of is this:
let identifier1Entered = !patron.identifier1.isEmpty
guard let id2 = patron.identifier2 where !id2.isEmpty || identifier1Entered
else { return }
But it requires that identifier2 is not nil, which is incorrect, and as far as I know, there's no way to use optional binding with || in if or guard statements. Not to mention that I feel it's less clear and readable than the force-unwrapping.
Anyone have a clear, more Swifty solution?
Two possible solutions using optional chaining:
let identifier2Entered = patron.identifier2?.isEmpty == false
let identifier2Entered = !(patron.identifier2?.isEmpty ?? true)
If patron.identifier2 is nil then patron.identifier2?.isEmpty
evaluates to nil, and you'll get false as a result.