@unknown default has been introduced in Swift 5 with SE-0192. It’s a new addition to the way we can work with Swift enums and helps us to prepare for future changes. After updating your project to Swift 5 you might end up with a new warning in Xcode 10.2:
Switch covers known cases, but ‘UNAuthorizationStatus’ may have additional unknown values, possibly added in future versions
Transform Your Career with the iOS Lead Essentials — Black Friday Offer This Black Friday, unlock over 40 hours of expert training, mentorship, and community support to secure your place among the best devs. Click for early access to this limited offer.
Basically, Swift warns you to be prepared for future changes.
Why do we need @unknown default to prepare for the future?
It’s quite an interesting question! The reason is Apple’s established process for evolving APIs. Whenever Apple adds a new enum case, it’s a source-breaking change. Say, for example, Apple introduces a new UNAuthorizationStatus
case in the future, your project will not compile if you would’ve handled each case individually.
Frozen vs non-frozen enums
The change comes with so-called frozen and non-frozen enums. It basically means that frozen enums will never get any new cases. When dealing with non-frozen enums the @unknown keyword ensures that clients handle any future cases. For now, it looks like Apple made a decision based on expectations and made some enums frozen and some not. You can find the full list here.
Do I ever need the @unknown case with my own enums?
Quoting from the Swift Evolution proposal:
A key note: in this version of the proposal, nothing changes for user-defined Swift enums. This only affects C enums and enums in the standard library and overlays today. (This refers to libraries that Apple could hypothetically ship with its OSs, as it does with Foundation.framework and the Objective-C runtime.) The features described here may be used by third-party libraries in the future.
In other words, unless you defined your enums in C, you’ll not create warnings on implementation level when dealing with your own defined enums.
How to use @unknown default
In the following example, we’re switching between user notification authorization statuses. This would’ve worked fine in Swift 4.2, but now triggers a warning.
switch userNotificationsAuthorizationStatus {
case .notDetermined:
requestPermission()
case .authorized, .denied, .provisional:
// No need to request permission.
print("Didn't request permission for User Notifications")
}
Therefore, we can use a combination of the fallthrough
keyword together with the new @unknown keyword.
switch userNotificationsAuthorizationStatus {
case .notDetermined:
requestPermission()
case .authorized, .denied, .provisional:
fallthrough
@unknown default:
// No need to request permission.
print("Didn't request permission for User Notifications")
}
The difference between default and @unknown default
@unknown default basically works the same as the regular default and therefore, matches any value. The main difference is that the compiler will produce a warning if all known elements of the enum have not yet been matched. New enum cases remain source-compatible as a result of throwing a warning instead of an error.
You can see the differences in the following two images. In this code example, I didn’t cover the authorized
enum case. Without @unknown, we’re not warned and just handling the case as a “catch all”. With @unknown, we’re warned that we didn’t handle the authorized
case.
Conclusion
The main point to take here; update your code to Swift 5 and check your warnings whenever a new iOS version comes out. It might be that there’s a new enum case for you to take care of!