Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using "where" clauses to produce optional types in Swift arithmetic

I would like to trigger conditional logic based around certain UI relationships during user interaction (in this case, I want to call a method when a user scrolls to a certain point in a UIScrollView). I would expect the following line of code to do this legally, since it is quite expressive:

func scrollViewDidScroll(scrollView: UIScrollView) {
    guard let overlap = scrollView.contentOffset.y - 220 where overlap > 0 else {
        return
    }

    reactToScrollOverlap(of: overlap)
}

However, I get the error that the guard let requires an optional type. That's reasonable, but I expected in this case that the where clause would naturally introduce an optional, since if the arithmetic works out wrong then there is no matching value of overlap.

Is there a way to use guard let (or, alternatively, if let) such that included where clauses stipulate conditions on the outcomes of arithmetic between Int, CGFloat, or other primitive/primitive-like types?

like image 463
qqq Avatar asked Jun 03 '16 03:06

qqq


3 Answers

guard let value = someOptionalValue {
}

if let value = someOptionalValue {
}

These are the way how you bind an optionals to a variable. If you are using guard let or if let you are using to get a value from optional types only.

and where clause will be triggered only when all the optionals have a value that precedes the where clause.

I think what you want to do is something like this:

let delta = scrollView.contentOffset.y - 220

if delta > 0 {

} else {

}

I would prefer clarity over brevity.

Edit:

Here is a better way to do it I think:

let yOffset        = scrollView.contentOffset.y
let newOffset:Int? = yOffset > 220 ? yOffset : nil
like image 133
Prajeet Shrestha Avatar answered Nov 20 '22 00:11

Prajeet Shrestha


guard and if let statements are normally only used to unwrap optionals. I'm not really thrilled with this solution, but you could cast scrollView.contentOffset.y as an Optional<CGFloat> to get the behavior you want:

guard let overlap = scrollView.contentOffset.y - 220 as CGFloat? where overlap > 0 else {
    return
}
like image 25
JAL Avatar answered Nov 20 '22 01:11

JAL


You are doing 3 things in one expression - declaring a variable (constant), assigning it and checking its value.

Declaring a variable in expressions is usually frowned upon, Swift does not really enable it. With one exception - unwrapping of optionals. You are not unwrapping an optional so just split the expression correctly into a declaration and a comparison:

let overlap = contentOffset.y - 220

guard overlap > 0 else {
    return
}

Another option is to use the case let pattern. I am not a big fan of it but it's probably what you want:

guard case let overlap = contentOffset.y - 220 where overlap > 0 else {
    return
}

print("overlap:", overlap)
like image 2
Sulthan Avatar answered Nov 20 '22 00:11

Sulthan