Swift error: guard body must not fall through
The guard
statement needs to have a something to take the flow of the program away from the enclosing scope (e.g. most likely case is return
to return from the function). This is required as the condition that guard is guarding will not be valid, so the program flow needs to go elsewhere!
Documentation:
The else clause of a guard statement is required, and must either call
a function marked with the noreturn attribute or transfer program
control outside the guard statement’s enclosing scope using one of the
following statements:
- return
- break
- continue
- throw
Getting guard body may not fall through error when setting up Google Analytics on iOS Project (in Swift)
guard let
function needs to exit the current scope of your gai
variable. So you need to modify your code to
guard let gai = GAI.sharedInstance() else {
assert(false, "Google Analytics not configured correctly")
return true//Base on your function return type, it may be returning something else
}
Here is the document:
The else clause of a guard statement is required, and must either call
a function marked with the noreturn attribute or transfer program
control outside the guard statement’s enclosing scope using one of the
following statements:return break continue throw
Guard statement in Swift has error if using return
The error is saying that your guard
statement is within a func()
that has an expected return value of some type
For example in the greet()
function a String
is returned… so the guard
statement must return a String
value. The type
of the value you have to return from your guard
statement will depend on the function that contains it.
func greet(person: String, day: String) -> String {
guard person != "Homer" else {
return "Sorry, no Homer's allowed"
}
return "Hello \(person), have a great \(day)"
}
greet(person: "Homer", day: "Monday")
greet(person: "Douglas", day: "Thursday")
If the String
"Sorry, no Homer's allowed" isn't returned in the example greet()
function you will see the same problem:
A guard
statement simply protects against an unusable state for the function it's enclosed in. So the return
statement of a guard
is just a form of early return
for the function, as such, it must return the same type as the functions definition.
In the greet()
function above the definition specifies that a String
is returned (-> String
) , so the return
inside the guard
's else block must also return a String
.
Swift: Benefit of using a guard-statement?
I don't think that is a very good example of using guard, it is more common to use it with variables that might be nil (aka optional) or functions that might return nil. I suggest you read about the guard statement in the Swift Programming Language book (just scroll down a bit to "Early Exit")
We could make a better example from your code that is lacking some validation
func getEmail(email: String?) -> String? {
guard let input = email, !input.isEmpty else {
return nil
}
return input + "@somewhere.com"
}
Here we use guard to check that the parameter email
is not nil by assigning it to a local variable input
. If it is nil the function will return nil and otherwise it will check if it is empty and then it will also return.
If it is ok the function will continue and create and return an email address. Note that the function is declared to return an optional string since I think it is much clearer if a function like this returns nil rather than an empty string if it fails.
If the Swift 'guard' statement must exit scope, what is the definition of scope?
It is totally possible to do what you envision, it just happens to not be what that particular code does. return
always exits a method, not the local scope. To do what you wish, you can use a label, and break
:
func testGuardControlFlow () {
let x = 2
let y = 2
func embededFunc () {
breakLabel:
if y == 2 {
guard x == 1 else {
print("oops, number is not 1")
break breakLabel
}
print ("from in embededFunc")
}
print ("I still want this to print even if x != 1")
}
embededFunc()
print("Great, return still allows this to be printed.")
}
testGuardControlFlow()
To add on to vadian's answer:
guard
forces you to exit the scope using a control transfer statement. There are 4 available to you:
return
andthrow
both exit the function/methodcontinue
can be used within loops (while
/for
/repeat-while
)break
can be used in loops (while
/for
/repeat-while
) to exit the immediate scope. Specifying a label to break to will allow you to exit multiple scopes at once (e.g. breaking out of nested loop structure). When using a label,break
can also be used inif
scopes.
Additionally, you may exit the scope by calling a function that returns Never
, such as fatalError
.
Using the guard condition in the body of statement
As the error states, you can't use a variable that you bound in the guard statement inside of the guard statement's body. The variable only gets bound in the case where the guard body is not entered. You also aren't differentiating between the cases where your response is nil and where your status code isn't 200.
You should break the statements into two different checks:
guard let httpResponse = response as? NSHTTPURLResponse else {
return NSError(domain: "Error with request", code: 1, userInfo: [NSLocalizedDescriptionKey: "Invalid response: \(response)"])
}
guard httpResponse.statusCode == 200 else {
return NSError(domain: "Error with request", code: 1, userInfo: [NSLocalizedDescriptionKey: "Recieved the following status code: \(httpResponse.statusCode)"])
}
Don't try to minimize the number of lines of code at the expense of readability or correctness.
Related Topics
Can a Swift Property Wrapper Reference the Owner of the Property Its Wrapping
Using Os_Log to Log Function Arguments, or Other Dynamic Data
How to Get Day and Month from Date Type - Swift 4
Using Swift to Disable Sleep/Screen Saver for Osx
In Swift, Why Does Assigning to a Static Variable Also Invoke Its Getter
Type Ccc Doesnt Conform to Protocol 'Nsobjectprotocol'
How Do Closures Capture Values from Previous Calls
Error When Using Generic as Property Type in Swift
Clgeocoder in Swift - Unable to Return String When Using Reversegeocodelocation
Filter by Multiple Array Conditions
Failed to Get Descriptors for Extensionbundleid
Swift Realm, Load the Pre-Populated Database the Right Way
How to Append a Character to a String in Swift
Why Does My Version of Filter Perform So Differently Than Swifts
Realm Mobile Platform, How to Connect While Offline
Use 'Self' as a Default Parameter
Why Does an @Objc Enum Have a Different Description Than a Pure Swift Enum