Swift Syntax Question

Hello Apple Developer Community,
First of all, I am a total newbie to the Swift programming language.
I am trying to ship my first app with Xcode. I thought it would make sense to first educate myself about the basics of Xcode and Swift. I've been reading this article as a starting point: https://developer.apple.com/library/archive/referencelibrary/GettingStarted/DevelopiOSAppsSwift/index.html#//apple_ref/doc/uid/TP40015214-CH2-SW1

Coming from java, I find the syntax of Swift to be extremely complicated, obscure, unintuitive, and frankly hard to understand.

Check the following statement for example, found in Working with Table Views >> Implement Navigation

guard let button = sender as? UIBarButtonItem, button === saveButton else {
  os_log("The save button was not pressed, cancelling", log: OSLog.default, type: .debug)
  return
}

So I have a few questions about the above code:
I understand that the as keyword is the down-cast operator. But why is there a "?" after it? What's the difference between as and as?
I thought the else clause comes immediately after the initial statement, in this case button = sender. What's the equality check button === saveButton after the comma? Does this mean that the downcast has to work AND button must equal saveButton in order for the else clause at the end to not fire?

Many thanks in advance! And thank you for your patience 😉
KC

Replies

Well, lmearning a new language with strong experience of another is always confusing.

For sure, someone coming from Swift to Java would experience the same trouble.


Consider the simple statement


let button = sender as UIBarButtonItem


You would probably get an error as: 'Any' is not convertible to 'UIBarButtonItem'; did you mean to use 'as!' to force downcast?


So, you have to force downcast with as!


But this casting may fail (if sender cannot be cast to UIBarButtonItem) and you would end up with a crash.


so, if is safer to use as?: this tries to force casting, and if it fails, it graciously return nil, and your guard statement will handle it as needed.


Read « The Swift Programming Language (Swift 4). » Apple Books.

« Downcasting

A constant or variable of a certain class type may actually refer to an instance of a subclass behind the scenes. Where you believe this is the case, you can try to downcast to the subclass type with a type cast operator (as? or as!).


Because downcasting can fail, the type cast operator comes in two different forms. The conditional form, as?, returns an optional value of the type you are trying to downcast to. The forced form, as!, attempts the downcast and force-unwraps the result as a single compound action.


Use the conditional form of the type cast operator (as?) when you are not sure if the downcast will succeed. This form of the operator will always return an optional value, and the value will be nil if the downcast was not possible. This enables you to check for a successful downcast.


Use the forced form of the type cast operator (as!) only when you are sure that the downcast will always succeed. This form of the operator will trigger a runtime error if you try to downcast to an incorrect class type. »

I understand that the as keyword is the down-cast operator. But why is there a "?" after it? What's the difference between as and as?

In Swift, `as`-casting is used for always-successful casting, and `as?` is for sometimes-fails casting, which returns `nil` on fails.


Don't you want to distinguish two types of casting which may make your code safer?


I thought the else clause comes immediately after the initial statement, in this case button = sender. What's the equality check button === saveButton after the comma? Does this mean that the downcast has to work AND button must equal saveButton in order for the else clause at the end to not fire?


`guard` is introduced into Swift, to help implementing early-exit pattern. It works only in some block context.

Some code using `guard`...

    guard <some condition> else {
        <some code exiting the block>
    }
    <statements in case condition is met>
    ...

is equivalent to an `if` statement...

    if <some condition> {
        <statements in case condition is met>
        ...
    } else {
        <some code exiting the block>
    }


You know that deeply nested `if` statements are hard to read and often cause simple mistakes. `guard` helps to improve the readability.


In your case, the `guard` staetment checks two conditions,

Check if `sender as? UIBarButtonItem` is not nil, if it actually is not nil, establishes the new variable binding `button` with the unwrapped value.

Chack if `button` (which is the newly established local constant) has the same reference as `saveButton`


Two checks are evaluated as AND-meaning as you described,

and if the condition is met, the evaluation of the block continues to the next statement following the `guard` statement. The established variable bindings are still valid in this case.

And if not, `else` is a good term used in this case, the evaluation goes inside the code-block following `else` and you need to exit the enclosing block.