Exhaustive condition of switch case in Swift
Swift only truly verifies that a switch
block is exhaustive when working with enum
types. Even a switching on Bool
requires a default
block in addition to true
and false
:
var b = true
switch b {
case true: println("true")
case false: println("false")
}
// error: switch must be exhaustive, consider adding a default clause
With an enum
, however, the compiler is happy to only look at the two cases:
enum MyBool {
case True
case False
}
var b = MyBool.True
switch b {
case .True: println("true")
case .False: println("false")
}
If you need to include a default
block for the compiler's sake but don't have anything for it to do, the break
keyword comes in handy:
var b = true
switch b {
case true: println("true")
case false: println("false")
default: break
}
Can a swift switch be exhaustive for type Double without a default case?
No because only enum types can be exhaustively checked.
But in this case, the problem is even deeper. Even if Integers could be exhaustively checked, you still couldn't exhaustively check Double without a where
clause. One of the options is .nan
("not a number"), which you're not considering. So you might think to just add that case:
case .nan:
yAxisMinimum = .nan
Not only won't this make it exhaustive, it won't even work the way you'd expect.
var minY = Double.nan
switch minY {
case -(Double.infinity)..<0.9:
yAxisMinimum = 0.0
// ...
case .nan:
yAxisMinimum = .nan
default:
yAxisMinimum = 0
}
yAxisMinimum // 0
Why? Because of this:
var minY = Double.nan
minY == .nan // false
NaN is unequal to everything, including NaN. So there's no way to include it directly in a switch statement. You have to use a where
clause:
case _ where minY.isNaN:
yAxisMinimum = .nan
And that's definitely beyond the compiler's ability to validate.
Switch must be exhaustive in Xcode 12
In WWDC 2020, iOS 14 Apple introduced a new feature that will give limited access to the photo library. You are missing .limited
case for outer main Switch. Your updated code:
switch PHPhotoLibrary.authorizationStatus(for: .readWrite) {
case .notDetermined:
// ask for access
case .restricted, .denied:
// sorry
case .authorized:
// we have full access
// new option:
case .limited:
// we only got access to a part of the library
}
For More, you can check here
Switch statement must be exhaustive
Xcode checks if the switch statement is exhaustive only if you're switching enums. For every other case, it checks if there is a default statement, and if not, it puts up a warning.
You can either use enums, or squelch the warning if you want to, or, just add the missing default statement doing nothing.
Noop for Swift's Exhaustive Switch Statements
According to the book, you need to use break
there:
The scope of each case can’t be empty. As a result, you must include at least one statement following the colon (:) of each case label. Use a single
break
statement if you don’t intend to execute any code in the body of a matched case.
Swift switch statement considered all cases of Int, but compiler still display error
Update for Swift 3: Swift 3 introduced ClosedRange
which makes
it possible to define a range like 1...Int.max
including the
largest possible integer (compare Ranges in Swift 3). So this compiles and works as expected,
but still requires a default case to satisfy the compiler:
extension Int {
enum Kind {
case negative, zero, positive
}
var kind: Kind {
switch self {
case 0:
return .zero
case 1...Int.max:
return .positive
case Int.min...(-1):
return .negative
default:
fatalError("Oops, this should not happen")
}
}
}
There are other bug reports where the Swift compiler does not
correctly determine the exhaustiveness of switch-statements, such
as https://bugs.swift.org/browse/SR-766, where Apple engineer Joe Groff
commented:
Unfortunately, integer operations like '...' and '<' are just plain functions to Swift, so it'd be difficult to do this kind of analysis. Even with special case understanding of integer intervals, I think there are still cases in the full generality of pattern matching for which exhaustiveness matching would be undecidable. We may eventually be able to handle some cases, but there will always be special cases involved in doing so.
Old answer: The compiler is not so smart to recognize that you have covered
all possible cases. One possible solution is to add a default
case with a fatalError()
:
var kind: Kind {
switch self {
case 0:
return .Zero
case let x where x > 0:
return .Positive
case let x where x < 0:
return .Negative
default:
fatalError("Oops, this should not happen")
}
}
Or make case 0:
the default case:
var kind: Kind {
switch self {
case let x where x > 0:
return .Positive
case let x where x < 0:
return .Negative
default:
return .Zero
}
}
(Remark: I initially thought that the following would work correctly
without needed a default case:
var kind: Kind {
switch self {
case 0:
return .Zero
case 1 ... Int.max:
return .Positive
case Int.min ... -1:
return .Negative
}
}
However, this compiles, but aborts at runtime because you cannot
create the range 1 ... Int.max
. More information around this
problem can be found in the article Ranges and Intervals in Swift.)
Related Topics
How to Correctly Handle Weak Self in Swift Blocks with Arguments
Extract Uiimage from Nsattributed String
Xcode 9 - "Fixed Width Constraints May Cause Clipping" and Other Localization Warnings
Navigation Bar Rightbaritem Image-Button Bug iOS 11
How to Make a Background Image Scale to Screen Size in Swift
How to Obtain a Dynamic Table View Section Header Height Using Auto Layout
Use and Access Existing SQLite Database on iOS
(Swift) How to Print "\" Character in a String
How to Calculate Uilabel Width Based on Text Length
Crashlytics: "We'Re Missing a Dsym to Process Crashes"
Changing Vc Issue in Swift. How to Pass Data Between Views in Tab Bar Controller
iOS - Uiimageview - How to Handle Uiimage Image Orientation
Swiftui Navigationview Navigationbartitle Layoutconstraints Issue
Ios9 Does Not Load Insecure Resources from a Secure Page (Ssl/Https)