Last active
August 3, 2018 06:14
-
-
Save designatednerd/390016f38c7f9559484c3bdcace066e1 to your computer and use it in GitHub Desktop.
Swift 3 Helpers for getting all the cases of a given enum [Swift 3]
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
/** | |
A swift protocol to make any Int enum able to count its cases. | |
Super-useful for making enums to help you deal with sections in tableviews without having to maintain a case for the count of the enum. | |
Originally developed by Logan Wright for Swift 2.0 here: | |
https://gist.github.com/LoganWright/c8a26b1faf538e40f747 | |
Based on this and the subsequent 3 slides from my talk about | |
Laziness-Driven Development at CocoaConf Boston 2015: | |
https://speakerdeck.com/designatednerd/laziness-driven-development-in-ios-cocoaconf-boston-september-2015?slide=28 | |
*/ | |
public protocol CountableIntEnum { | |
/// - parameter rawValue: The raw Int value. Matches the initializer of RawRepresentable without the Self restrictions. | |
init?(rawValue: Int) | |
} | |
//MARK: Default Implementation | |
public extension CountableIntEnum { | |
/** | |
- returns: A generated array of all the cases in this enum. Mostly useful for calling with | |
.count so you can get the number of items in this enum. | |
*/ | |
public static var AllCases: [Self] { | |
var caseIndex: Int = 0 | |
let generator: AnyIterator<Self> = AnyIterator { | |
let _generator = Self(rawValue: caseIndex) | |
caseIndex += 1 | |
return _generator | |
} | |
return Array(generator) | |
} | |
/** | |
Method to consolidate fatal erroring out if something ain't there. | |
- parameter index: The index (indexPath.row or indexPath.section, usually) of the thing you want to grab. | |
- returns: The retrieved enum case. Fatal errors if it can't find it. | |
*/ | |
public static func forIndex(_ index: Int) -> Self { | |
guard let rowOrSection = Self(rawValue: index) else { | |
fatalError("Issue unwrapping row.") | |
} | |
return rowOrSection | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
public extension RawRepresentable { | |
/** | |
Method to consolidate fatal erroring if something that should definitely be in an enum which conforms | |
to `RawRepresentable` isn't there. | |
This means at the call site where you're trying to instantiate from a raw value instead of | |
``` | |
guard let section = Sections(rawValue: sectionIndex) else { fatalError() } | |
switch section {... | |
``` | |
You can just do | |
``` | |
switch Sections.forValue(sectionIndex) {... | |
``` | |
- parameter value: The raw value (indexPath.row or indexPath.section, usually) of the thing you want to grab. | |
- returns: The retrieved enum case. Fatal errors if it can't find it. | |
*/ | |
static func forValue(_ value: RawValue) -> Self { | |
guard let type = Self.init(rawValue: value) else { | |
fatalError("Could not instantiate a \(Self.self) with value \(value)") | |
} | |
return type | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
/// A protocol to allow grabbing an array of all the cases of a string enum. | |
/// Inspired by: http://stackoverflow.com/a/32429125/681493 | |
public protocol StringCaseListable { | |
/// - parameter rawValue: The raw string value. Matches the initializer of RawRepresentable without the Self restrictions. | |
init?(rawValue: String) | |
} | |
//MARK: - Default Implementation | |
public extension StringCaseListable { | |
/// - returns: A generated array of all the cases in this enum. | |
static var AllCases: [Self] { | |
var caseIndex: Int = 0 | |
// Create an iterator | |
let generator: AnyIterator<Self> = AnyIterator { | |
// In which each time it goes around, the case index is used | |
let current: Self = withUnsafePointer(to: &caseIndex) { | |
// To grab the appropriate memory for one of this type, and grab it's pointee | |
$0.withMemoryRebound(to: Self.self, capacity: 1) { $0.pointee } | |
} | |
caseIndex += 1 | |
return current | |
} | |
return Array(generator) | |
} | |
} |
when enum
implement CodingKey
enum Food: String, CodingKey, StringCaseListable {
case apple = "Apple"
case banana = "b"
}
for key in Food.AllCases {
print(key)
}
// prints Food(stringValue: "Apple", intValue: nil)
// prints Food(stringValue: "b", intValue: nil)
But I excepted prints apple and banana.
It seems CodingKey
breaks down the description of Food
and can not get original key anymore. Any suggestion ?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note that in Swift 4.2, the
CaseIterable
protocol will take care of generating your list of items in the enum. Once that lands, you should definitely use that instead of eitherStringCaseListable
orCountableIntEnum
.The
RawRepresentable
extension just added will give you the ability to centralize fatal errors on anyRawRepresentable
type. If you want to constrain it to justCaseIterable
types, you can do that by updating the declaration to: