How to Tell Which Guard Statement Failed

How do I tell which guard statement failed?

Erica Sadun just wrote a good blog post on this exact topic.

Her solution was to hi-jack the where clause and use it to keep track of which guard statements pass. Each successful guard condition using the diagnose method will print the file name and the line number to the console. The guard condition following the last diagnose print statement is the one that failed. The solution looked like this:

func diagnose(file: String = #file, line: Int = #line) -> Bool {
print("Testing \(file):\(line)")
return true
}

// ...

let dictionary: [String : AnyObject] = [
"one" : "one"
"two" : "two"
"three" : 3
]

guard
// This line will print the file and line number
let one = dictionary["one"] as? String where diagnose(),
// This line will print the file and line number
let two = dictionary["two"] as? String where diagnose(),
// This line will NOT be printed. So it is the one that failed.
let three = dictionary["three"] as? String where diagnose()
else {
// ...
}

Erica's write-up on this topic can be found here

Guard statement in swift for error handling

You could use the where clause to check for non-nil and non-empty

guard let num1 = num1Input.text where !num1.isEmpty else {
show("No input in first box")
return
}

How can I make sure my guard statement doesn't proceed with a nil value?

Your code is correct and probably never will enter the guard clause. Here you are setting values of variables base on, I think, UIText fields. This fields when empty are not null. It's important to understand that an empty string is not the same thing as a null value. An empty string, represented as "" is still a string. A null value is, like JavaScript coders like to talk: has an undefined type. Your guard clause will fail only when you try to set a non nil property to nil value.

To solve this, you just change your guard clause to something like:

guard emailField.text.isEmpty == false, passwordField.text.isEmpty == false

Or

guard !emailField.text.isEmpty, !passwordField.text.isEmpty

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:

broken guard statement

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.

How to use guard statement to detect nil after an assignment?

The other answers show you how to solve your issue, but doesn't really explain why this error occurs, so I thought I'd pitch in on that.


The guard let ... else statement, much like if let ..., attempts to bind the unwrapped value of an optional---generally as long as this is not nil---to a non-optional immutable of the same underlying type; using optional binding

var a: Int? = 5
if let b = a {
// b unwrapped, type inferred to non-optional type Int
print(b) // "5"
}

The above binding would fail if a had the value nil, as b, as per default (by type inference), is of type Int which cannot hold nil.

In this context, it makes no sense to explicitly declare b to be an implicitly unwrapped optional, as this will allow a successful binding even if a is nil. An equivalently non-sense block would be to explicitly declare b to be an optional, whereafter the "attempted optional binding" of optional a (Int?) to optional b (Int?) would naturally always succeed, and the if let ... block reduces to a completely redundant block-local assignment.

a = nil

if let b: Int! = a {
print(b) // "nil"
// wups, we managed to bind a to b even though a is nil ...

// note also this peculiarity
print(b.dynamicType) // Optional<Int>
let c: Int! = nil
print(c.dynamicType) // ImplicitlyUnwrappedOptional<Int>
}

if let b: Int? = a {
print(b) // nil
// wups, we managed to bind a to b even though a is nil ...
}

Note the peculiarity that no matter if we explicitly specify b to be of type Int? (optional) or type Int! (implicitly unwrapped optional), the binded immutable b passing into the if let block is, for both cases, just a regular optional (of type Int?). This explains why you need to unwrap event (event!.iconImgData) after the guard let clause, even though we declared it to be of an implicitly unwrapped type.

Hence, in your example, your guard let ... else statement will not catch cases where eventsImagesLoading.removeValueForKey(location) is nil, as the binding to event (which is of implicitly unwrapped optional type Event!) will success even for nil cases.

func foo() {
let bar : Int? = nil
guard let _: Int! = bar else {
print("this is surely nil")
return

}
print("but an implicitly unwrapped optional will fall through")
}
foo() // "but an implicitly unwrapped optional will fall through"

You should generally only use implicitly unwrapped optionals for immutables where you need delayed initialization (value nil until initialized). After initialization of an implicitly unwrapped optional, its value should never be nil (whereas in the example above, it's value is, after initialization by optional binding, just that; nil).

Also, you should generally let the compiler infer the non-optional type of the immutable to which you are trying to bind in the guard let INFER_THIS = ... else or if let INFER_THIS = ... clauses.


We could ponder over whether it should even be allowed to use optional binding to optional types (guaranteed success), but that is another discussion.

Force error in guard statement?

An NSError object encapsulates information about an error condition in an extendable, object-oriented manner. It consists of a predefined error domain, a domain-specific error code, and a user info dictionary containing application-specific information. more check Apple Doc

 guard let statusCode = (response as? HTTPURLResponse)?.statusCode, statusCode >= 200 && statusCode <= 299 else {
print("Your request returned a status code other than 2xx!")
//How can I force an error?
let error = NSError(domain: "statusCode",
code: (response as? HTTPURLResponse)?.statusCode,
userInfo: [NSLocalizedDescriptionKey: "Your request returned a status code other than 2xx!"])

self.delegate.errorWeather(error: error )
return
}


Related Topics



Leave a reply



Submit