Stupid Enum Tricks in Swift and Kotlin - We Are Developers, Vienna, Austria, May 2018
Enums in Swift and enum classes in Kotlin are extremely powerful ways to deal with a known set of possible values. Learn how to use these tools to help you cleaner, safer code, and how to push the boundaries of what's possible with enums.
STUPID ENUM TRICKS IN SWIFT AND KOTLIN WE ARE DEVELOPERS | VIENNA, AUSTRIA | MAY 2018 BAKKENBAECK.COM | JUSTHUM.COM | DESIGNATEDNERD.COM BY ELLEN SHAPIRO | @DESIGNATEDNERD
SWIFT func colorForName(_ name: String) -> UIColor? { switch name { case ColorName.red.rawValue: return UIColor.red case ColorName.orange.rawValue: return UIColor.orange // same for other ColorName cases default: return nil }
SWIFT var currentColor: TrafficLightColor = .red switch currentColor { case .red: print("STOP RIGHT THERE") case .yellow: print("Whoa, slow down there, buddy.") case .green: print("Go, go, go!") }
SWIFT var currentColor: TrafficLightColor = .red switch currentColor { case .red: print("STOP RIGHT THERE") case .green: print("Go, go, go!") // Error: Unhandled case! }
SWIFT var currentColor: TrafficLightColor = .red switch currentColor { case .red: print("STOP RIGHT THERE") case .yellow, .green: print("Go, go, go!") }
KOTLIN Instance Gets You Example instance.name String value of case's written name Days.THURSDAY.name is "THURSDAY", Days.Thursday.name is "Thursday" instance.ordinal Index of case in list of cases
SWIFT Codable class User: Codable { let userName: String let email: String let latitude: Double let longitude: Double enum CodingKeys: String, CodingKey { case userName = "user_name" case email = "email_address" case latitude = "lat" case longitude = "long" } }
SWIFT enum SettingsSection: Int, CaseIterable { case profile case legalese case contact case logout } // Automatically generated: static var allCases: [SettingsSection]
SWIFT enum LandingScreenButton { case signIn case signUp case viewTerms var localizedTitle: String { switch self { case .signIn: return NSLocalizedString("Sign In", "Sign in button title") case .signUp: return NSLocalizedString("Sign Up", "Sign up button title") case .viewTerms: return NSLocalizedString("View Terms & Conditions", "Title for button to view legalese") } }
SWIFT public enum LandingScreenButton { case signIn case signUp case viewTerms public var localizedTitle: String { switch self { case .signIn: return NSLocalizedString("Sign In", "Sign in button title") case .signUp: return NSLocalizedString("Sign Up", "Sign up button title") case .viewTerms: return NSLocalizedString("View Terms & Conditions", "Title for button to view legalese") } }
SWIFT / IOS: AFTER public enum Asset: String { case cinnamon_rolls case innocent case no case snack case window var image: UIImage { return UIImage(named: self.rawValue)! } }
SWIFT / IOS: TESTS! func testAllAssetsAreThere() { for asset in Asset.allCases { XCTassertNotNil(UIImage(named: asset.rawValue), "Image for \(asset.rawValue) was nil!") } }
SWIFT / IOS: TESTS! func testAllAssetsAreThere() { for asset in Asset.allCases { XCTassertNotNil(UIImage(named: asset.rawValue), "Image for \(asset.rawValue) was nil!") } } !!!!!!!
SWIFT: THE ENUM, REVISED enum MainStoryboardSegue: String, SeguePerforming { case toSignIn case toSignUp case toTerms case toCats case toCatsLoggedIn }
KOTLIN sealed class DownloadStateWithInfo { class NotStarted: DownloadStateWithInfo() class Downloading(val progress: Float): DownloadStateWithInfo() }
KOTLIN sealed class DownloadStateWithInfo { class NotStarted: DownloadStateWithInfo() class Downloading(val progress: Float): DownloadStateWithInfo() class Succeeded(val data: ByteArray): DownloadStateWithInfo() }
KOTLIN sealed class DownloadStateWithInfo { class NotStarted: DownloadStateWithInfo() class Downloading(val progress: Float): DownloadStateWithInfo() class Succeeded(val data: ByteArray): DownloadStateWithInfo() class Failed(val error: Error): DownloadStateWithInfo() }
KOTLIN sealed class DownloadStateWithInfo { class NotStarted: DownloadStateWithInfo() class Downloading(val progress: Float): DownloadStateWithInfo() class Succeeded(val data: ByteArray): DownloadStateWithInfo() class Failed(val error: Error): DownloadStateWithInfo() }
SWIFT: GOOD enum LandingScreenButton { // Stuff we saw before var localizedTitle: String { switch self { case .signIn: return NSLocalizedString("Sign In", "Sign in button title") case .signUp: return NSLocalizedString("Sign Up", "Sign up button title") case .viewTerms: return NSLocalizedString("View Terms & Conditions", "Title for button to view legalese") } }
SWIFT: OVER THE TOP enum LandingScreenButton { // Stuff we saw before func handleClick(in viewController: UIViewController) { switch self { case .signIn: viewController.navigationController? .pushViewController(SignInViewController(), animated: true) case .signUp: viewController.navigationController? .pushViewController(RegistrationViewController(), animated: true) case .viewTerms: viewController.present(LegaleseViewController(), animated: true) } } }
OBLIGATORY SUMMARY SLIDE > Enums are a great way to represent distinct state > Limit your cases, limit your bugs > Value determined by the current case -> computed var
OBLIGATORY SUMMARY SLIDE > Enums are a great way to represent distinct state > Limit your cases, limit your bugs > Value determined by the current case -> computed var > Generated enums help reduce stringly-typed code
OBLIGATORY SUMMARY SLIDE > Enums are a great way to represent distinct state > Limit your cases, limit your bugs > Value determined by the current case -> computed var > Generated enums help reduce stringly-typed code > Don't forget about separation of concerns
LINKS! > The Swift book's section on Enums: https://developer.apple.com/library/ content/documentation/Swift/Conceptual/ Swift_Programming_Language/ Enumerations.html > Kotlin Enum Class documentation: https://kotlinlang.org/docs/reference/ enum-classes.html