Have a variable with multiple types in Swift - ios

I would like to have a variable, which can have multiple types (only ones, I defined), like:
var example: String, Int = 0
example = "hi"
This variable should be able to hold only values of type Int and String.
Is this possible?
Thanks for your help ;)

An “enumeration with associated value” might be what you are looking for:
enum StringOrInt {
case string(String)
case int(Int)
}
You can either assign a string or an integer:
var value: StringOrInt
value = .string("Hello")
// ...
value = .int(123)
Retrieving the contents is done with a switch-statement:
switch value {
case .string(let s): print("String:", s)
case .int(let n): print("Int:", n)
}
If you declare conformance to the Equatable protocol then
you can also check values for equality:
enum StringOrInt: Equatable {
case string(String)
case int(Int)
}
let v = StringOrInt.string("Hi")
let w = StringOrInt.int(0)
if v == w { ... }

Here is how you can achieve it. Works exactly how you'd expect.
protocol StringOrInt { }
extension Int: StringOrInt { }
extension String: StringOrInt { }
var a: StringOrInt = "10"
a = 10 //> 10
a = "q" //> "q"
a = 0.8 //> Error
NB! I would not suggest you to use it in production code. It might be confusing for your teammates.
UPD: as #Martin R mentioned: Note that this restricts the possible types only “by convention.” Any module (or source file) can add a extension MyType: StringOrInt { } conformance.

No, this is not possible for classes, structs, etc.
But it is possible for protocols.
You can this:
protocol Walker {
func go()
}
protocol Sleeper {
func sleep()
}
var ab = Walker & Sleeper
or even
struct Person {
var name: String
}
var ab = Person & Walker & Sleeper
But I don't recomment use this way.
More useful this:
struct Person: Walker, Sleeper {
/// code
}
var ab = Person

You can use Tuple.
Example:
let example: (String, Int) = ("hi", 0)
And access each data by index:
let stringFromExampleTuple = example.0 // "hi"
let intFromtExampleTuple = example.1 // 0

Related

swift text with 2 variables and different language

i would like to translate a string, which have two variables inside.
at the moment, i use for translating this code:
NSLocalizedString("Name_In_Langauge_String_File",comment:"")
but how can i translate the following string?
This is a test with 100 Pictures and 50 Users
where 100 and 50 are variables.
Put this in you Localizable.strings:
"Name_In_Langauge_String_File" = "This is a test with %d Pictures and %d Users";
and in your code:
String.localizedStringWithFormat(
NSLocalizedString("Name_In_Langauge_String_File",
comment: ""),
pictures,
users)
In a project I was working on I noticed that we kept repeating the code to do the string formatting for the localization file. This meant you could not just use the value, you first needed to check what parameters were required. One way to avoid this problem is to use Swift enums. This method is also useful for unit testing your localizations.
Assume you have the following 3 localizations in your strings file:
"TestNoParams" = "This is a test message";
"TestOneParam" = "Hello %#";
"TestTwoParams" = "This is a test with %d Pictures and %d Users";
Now you can use the following enum, protocol and extension to reference your strings:
protocol LocalizationProtocol {
var key: String { get }
var value: String { get }
}
extension LocalizationProtocol {
private func localizationValue() -> String {
return NSLocalizedString(key, comment:key)
}
private func localizationValueWithFormat(parameters: CVarArgType...) -> String {
return String(format: localizationValue(), arguments: parameters)
}
}
enum Localizations: LocalizationProtocol {
case TestNoParams
case TestOneParam(name: String)
case TestPicturesAndUsers(pictures: Int, users: Int)
var key: String {
switch self {
case .TestNoParams: return "TestNoParams"
case .TestOneParam: return "TestOneParam"
case .TestPicturesAndUsers: return "TestTwoParams"
}
}
var value: String {
switch self {
case .TestOneParam(let name):
return localizationValueWithFormat(name)
case .TestPicturesAndUsers(let pictures, let users):
return localizationValueWithFormat(pictures, users)
default:
return localizationValue()
}
}
}
Now to use it you just need to call the enums value method:
let testNoParam = Localizations.TestNoParams.value
let testOneParam = Localizations.TestOneParam(name: "users name").value
let testTwoParams = Localizations.TestPicturesAndUsers(pictures: 4, users: 500).value
The example I have shown is simplified, but you can also nest enums to provide a nice grouping for your localizations. For instance you could have your enums nested by ViewController. This is an example for a welcome message: Localizations.Main.WelcomeMessage.value

iOS 9 Stanford Course in Swift - Lecture 1

I'm currently trying to complete the Swift Course on iTunes U and we are building a calculator. I'm having trouble understanding part of the code.
I added the code below that I thought was relevant from the file.
Here is what confuses me: why does operation(operand) compute the value for the UnaryOperation (i.e. the square root)? I see that when the CalculatorBrain class is called the dictionary is initialized, but when I print the dictionary out I just get something that looks like this: [✕: ✕, -: -, +: +, ⌹: ⌹, √: √]. So where/when does the program compute the square root when I click on the square root button?
Class CalculatorBrain
{
private enum Op: Printable
{
case Operand(Double)
case UnaryOperation(String, Double -> Double)
case BinaryOperation(String, (Double, Double) -> Double)
var description: String {
get {
switch self {
case .Operand(let operand):
return "\(operand)"
case .UnaryOperation(let symbol, _):
return symbol
case .BinaryOperation(let symbol, _):
return symbol
}
}
}
}
private var opStack = [Op]()
private var knownOps = [String: Op]()
init() {
func learnOp(op: Op) {
knownOps[op.description] = op
}
learnOp(Op.BinaryOperation("✕", *))
learnOp(Op.BinaryOperation("⌹") { $1 / $0 })
learnOp(Op.BinaryOperation("+", +))
learnOp(Op.BinaryOperation("-") { $0 - $1 })
learnOp(Op.UnaryOperation ("√", sqrt))
}
private func evaluate(ops: [Op]) -> (result: Double?, remainingOps: [Op])
{
if !ops.isEmpty {
var remainingOps = ops
let op = remainingOps.removeLast()
switch op {
case .Operand(let operand):
return (operand, remainingOps)
case .UnaryOperation(_, let operation):
let operandEvaluation = evaluate(remainingOps)
if let operand = operandEvaluation.result {
**return (operation(operand), operandEvaluation.remainingOps)**
}
// case.BinaryOperation(.....)
}
}
return (nil, ops)
}
func evaluate() -> Double? {
let (result, remainder) = evaluate(opStack)
return result
}
func pushOperand(operand: Double) -> Double? {
opStack.append(Op.Operand(operand))
return evaluate()
}
func performOperation(symbol: String) -> Double? {
if let operation = knownOps[symbol] {
opStack.append(operation)
}
return evaluate()
}
}
The Op enum implements the Printable protocol, which means it has a description: String property. When you print the Dictionary, you are sending [String : Op] to the println function which then tries to print the Op using its description.
The reason the description of the operators is the same as its key in the Dictionary is because the learnOp(op: Op) function sets the key to be op.description (knownOps[op.description] = op)
To see the effects of this, you could add a new operator learnOp(Op.UnaryOperation ("#", sqrt)) which will be printed as #:# inside of the knownOps Dictionary. (And if you add a new button for the # operator, it will also perform the square root operation)
Since the calculator is stack based, the operands get pushed on, then the operations. When evaluate() gets called, it calls evaluate(opStack) passing the entire stack through.
evaluate(ops: [Op]) then takes the to item off of the stack and evaluates the function after having calculated the operands.
As an example, lets say you want to calucalte sqrt(4 + 5).
You would push the items onto the stack, and it would look like: [ 4, 5, +, sqrt ]
Then evaluate(ops: [Op]) sees the sqrt and evaluates the operand with a recursive call. That call then evaluates + with two more recursive calls which return 5 and 4.
The tree of calls would look like this:
ops: [4, 5, +, sqrt] // Returns sqrt(9) = 3
|
ops: [4, 5, +] // Returns 4 + 5 = 9
____|_____
| |
ops: [4, 5] ops: [4]
return 5 return 4
I strongly recommend you put a breakpoint on the evaluate() -> Double? function and step through the program to see where it goes with different operands and operations.
learnOp(Op.UnaryOperation ("√", sqrt))
sqrt is a built in function, so you're teaching the calculator that "√" means it should perform the sqrt operation.

Raw value for enum case must be a literal

I have this enum:
enum GestureDirection:UInt {
case Up = 1 << 0
case Down = 1 << 1
case Left = 1 << 2
case Right = 1 << 3
}
But on every case I get error:
Raw value for enum case must be a literal
I dont get it.
Swift 1.2, Xcode 6.3.2
That's because 1 << 0 isn't a literal. You can use a binary literal which is a literal and is allowed there:
enum GestureDirection:UInt {
case Up = 0b000
case Down = 0b001
case Left = 0b010
case Right = 0b100
}
Enums only support raw-value-literals which are either numeric-literal (numbers) string-literal­ (strings) or boolean-literal­ (bool) per the language grammar.
Instead as a workaround and still give a good indication of what you're doing.
(Answer updated for Swift 5 and later. Solutions for older Swift versions can be found in the edit history.)
For attributes which are not mutually exclusive you can use a struct and declare conformance to the OptionSet protocol. The advantage is that you get all bit operations for free.
You just have to define the underlying storage type and the pre-defined values:
struct GestureDirection : OptionSet {
let rawValue : UInt8
static let top = Self(rawValue: 1 << 0)
static let down = Self(rawValue: 1 << 1)
static let left = Self(rawValue: 1 << 2)
static let right = Self(rawValue: 1 << 3)
}
Usage:
// Initialize:
var direction : GestureDirection = [ .top, .right ]
// Test:
if direction.contains(.top) {
// ...
}
// Add an option:
direction.insert(.left)
// Remove an option:
direction.remove(.right)
Swift 2.2 Version :
In my case I needed to Convert the String Enum Values to be used in Localisable Strings. So added this method inside my enum.
enum DisplayCellTitle: String {
case Clear
func labelTitle() -> String {
switch self {
case .Clear:
return "LBL_CLEAR".localizedWithComment("Clear")
}
}
}
And then Use it like so :
// Get the localised value of the Cell Label Title
let lblTitle = DisplayCellTitle.labelTitle(cellTitle)()
where cellTitle passed in is just one of these CellTitle Enum Values
You seems to want a bitwise support for your enums, but if you regards a translation of NS_OPTIONS Objective-C in Swift, that's not represented by a Swift Enum but a struct inherit from RawOptionSetType.
If you need example or instructions, you can look at this NSHipster article
That's could be done with something like this :
struct UIViewAutoresizing : RawOptionSetType {
init(_ value: UInt)
var value: UInt
static var None: UIViewAutoresizing { get }
static var FlexibleLeftMargin: UIViewAutoresizing { get }
static var FlexibleWidth: UIViewAutoresizing { get }
static var FlexibleRightMargin: UIViewAutoresizing { get }
static var FlexibleTopMargin: UIViewAutoresizing { get }
static var FlexibleHeight: UIViewAutoresizing { get }
static var FlexibleBottomMargin: UIViewAutoresizing { get }
}
Regards,

Swift: get number of values in an enum? Goal is to avoid hard coding number in random function [duplicate]

How can I determine the number of cases in a Swift enum?
(I would like to avoid manually enumerating through all the values, or using the old "enum_count trick" if possible.)
As of Swift 4.2 (Xcode 10) you can declare
conformance to the CaseIterable protocol, this works for all
enumerations without associated values:
enum Stuff: CaseIterable {
case first
case second
case third
case forth
}
The number of cases is now simply obtained with
print(Stuff.allCases.count) // 4
For more information, see
SE-0194 Derived Collection of Enum Cases
I have a blog post that goes into more detail on this, but as long as your enum's raw type is an integer, you can add a count this way:
enum Reindeer: Int {
case Dasher, Dancer, Prancer, Vixen, Comet, Cupid, Donner, Blitzen
case Rudolph
static let count: Int = {
var max: Int = 0
while let _ = Reindeer(rawValue: max) { max += 1 }
return max
}()
}
Xcode 10 update
Adopt the CaseIterable protocol in the enum, it provides a static allCases property which contains all enum cases as a Collection . Just use of its count property to know how many cases the enum has.
See Martin's answer for an example (and upvote his answers rather than mine)
Warning: the method below doesn't seem to work anymore.
I'm not aware of any generic method to count the number of enum cases. I've noticed however that the hashValue property of the enum cases is incremental, starting from zero, and with the order determined by the order in which the cases are declared. So, the hash of the last enum plus one corresponds to the number of cases.
For example with this enum:
enum Test {
case ONE
case TWO
case THREE
case FOUR
static var count: Int { return Test.FOUR.hashValue + 1}
}
count returns 4.
I cannot say if that's a rule or if it will ever change in the future, so use at your own risk :)
I define a reusable protocol which automatically performs the case count based on the approach posted by Nate Cook.
protocol CaseCountable {
static var caseCount: Int { get }
}
extension CaseCountable where Self: RawRepresentable, Self.RawValue == Int {
internal static var caseCount: Int {
var count = 0
while let _ = Self(rawValue: count) {
count += 1
}
return count
}
}
Then I can reuse this protocol for example as follows:
enum Planet : Int, CaseCountable {
case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
//..
print(Planet.caseCount)
Create static allValues array as shown in this answer
enum ProductCategory : String {
case Washers = "washers", Dryers = "dryers", Toasters = "toasters"
static let allValues = [Washers, Dryers, Toasters]
}
...
let count = ProductCategory.allValues.count
This is also helpful when you want to enumerate the values, and works for all Enum types
If the implementation doesn't have anything against using integer enums, you could add an extra member value called Count to represent the number of members in the enum - see example below:
enum TableViewSections : Int {
case Watchlist
case AddButton
case Count
}
Now you can get the number of members in the enum by calling, TableViewSections.Count.rawValue which will return 2 for the example above.
When you're handling the enum in a switch statement, make sure to throw an assertion failure when encountering the Count member where you don't expect it:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let currentSection: TableViewSections = TableViewSections.init(rawValue:section)!
switch(currentSection) {
case .Watchlist:
return watchlist.count
case .AddButton:
return 1
case .Count:
assert(false, "Invalid table view section!")
}
}
This kind of function is able to return the count of your enum.
Swift 2:
func enumCount<T: Hashable>(_: T.Type) -> Int {
var i = 1
while (withUnsafePointer(&i) { UnsafePointer<T>($0).memory }).hashValue != 0 {
i += 1
}
return i
}
Swift 3:
func enumCount<T: Hashable>(_: T.Type) -> Int {
var i = 1
while (withUnsafePointer(to: &i, {
return $0.withMemoryRebound(to: T.self, capacity: 1, { return $0.pointee })
}).hashValue != 0) {
i += 1
}
return i
}
String Enum with Index
enum eEventTabType : String {
case Search = "SEARCH"
case Inbox = "INBOX"
case Accepted = "ACCEPTED"
case Saved = "SAVED"
case Declined = "DECLINED"
case Organized = "ORGANIZED"
static let allValues = [Search, Inbox, Accepted, Saved, Declined, Organized]
var index : Int {
return eEventTabType.allValues.indexOf(self)!
}
}
count : eEventTabType.allValues.count
index : objeEventTabType.index
Enjoy :)
Oh hey everybody, what about unit tests?
func testEnumCountIsEqualToNumberOfItemsInEnum() {
var max: Int = 0
while let _ = Test(rawValue: max) { max += 1 }
XCTAssert(max == Test.count)
}
This combined with Antonio's solution:
enum Test {
case one
case two
case three
case four
static var count: Int { return Test.four.hashValue + 1}
}
in the main code gives you O(1) plus you get a failing test if someone adds an enum case five and doesn't update the implementation of count.
This function relies on 2 undocumented current(Swift 1.1) enum behavior:
Memory layout of enum is just a index of case. If case count is from 2 to 256, it's UInt8.
If the enum was bit-casted from invalid case index, its hashValue is 0
So use at your own risk :)
func enumCaseCount<T:Hashable>(t:T.Type) -> Int {
switch sizeof(t) {
case 0:
return 1
case 1:
for i in 2..<256 {
if unsafeBitCast(UInt8(i), t).hashValue == 0 {
return i
}
}
return 256
case 2:
for i in 257..<65536 {
if unsafeBitCast(UInt16(i), t).hashValue == 0 {
return i
}
}
return 65536
default:
fatalError("too many")
}
}
Usage:
enum Foo:String {
case C000 = "foo"
case C001 = "bar"
case C002 = "baz"
}
enumCaseCount(Foo) // -> 3
I wrote a simple extension which gives all enums where raw value is integer a count property:
extension RawRepresentable where RawValue: IntegerType {
static var count: Int {
var i: RawValue = 0
while let _ = Self(rawValue: i) {
i = i.successor()
}
return Int(i.toIntMax())
}
}
Unfortunately it gives the count property to OptionSetType where it won't work properly, so here is another version which requires explicit conformance to CaseCountable protocol for any enum which cases you want to count:
protocol CaseCountable: RawRepresentable {}
extension CaseCountable where RawValue: IntegerType {
static var count: Int {
var i: RawValue = 0
while let _ = Self(rawValue: i) {
i = i.successor()
}
return Int(i.toIntMax())
}
}
It's very similar to the approach posted by Tom Pelaia, but works with all integer types.
enum EnumNameType: Int {
case first
case second
case third
static var count: Int { return EnumNameType.third.rawValue + 1 }
}
print(EnumNameType.count) //3
OR
enum EnumNameType: Int {
case first
case second
case third
case count
}
print(EnumNameType.count.rawValue) //3
*On Swift 4.2 (Xcode 10) can use:
enum EnumNameType: CaseIterable {
case first
case second
case third
}
print(EnumNameType.allCases.count) //3
Of course, it's not dynamic but for many uses you can get by with a static var added to your Enum
static var count: Int{ return 7 }
and then use it as EnumName.count
For my use case, in a codebase where multiple people could be adding keys to an enum, and these cases should all be available in the allKeys property, it's important that allKeys be validated against the keys in the enum. This is to avoid someone forgetting to add their key to the all keys list. Matching the count of the allKeys array(first created as a set to avoid dupes) against the number of keys in the enum ensures that they are all present.
Some of the answers above show the way to achieve this in Swift 2 but none work in Swift 3. Here is the Swift 3 formatted version:
static func enumCount<T: Hashable>(_ t: T.Type) -> Int {
var i = 1
while (withUnsafePointer(to: &i) {
$0.withMemoryRebound(to:t.self, capacity:1) { $0.pointee.hashValue != 0 }
}) {
i += 1
}
return i
}
static var allKeys: [YourEnumTypeHere] {
var enumSize = enumCount(YourEnumTypeHere.self)
let keys: Set<YourEnumTypeHere> = [.all, .your, .cases, .here]
guard keys.count == enumSize else {
fatalError("Missmatch between allKeys(\(keys.count)) and actual keys(\(enumSize)) in enum.")
}
return Array(keys)
}
Depending on your use case, you might want to just run the test in development to avoid the overhead of using allKeys on each request
Why do you make it all so complex? The SIMPLEST counter of Int enum is to add:
case Count
In the end. And... viola - now you have the count - fast and simple
enum WeekDays : String , CaseIterable
{
case monday = "Mon"
case tuesday = "Tue"
case wednesday = "Wed"
case thursday = "Thu"
case friday = "Fri"
case saturday = "Sat"
case sunday = "Sun"
}
var weekdays = WeekDays.AllCases()
print("\(weekdays.count)")
If you don't want to base your code in the last enum you can create this function inside your enum.
func getNumberOfItems() -> Int {
var i:Int = 0
var exit:Bool = false
while !exit {
if let menuIndex = MenuIndex(rawValue: i) {
i++
}else{
exit = true
}
}
return i
}
A Swift 3 version working with Int type enums:
protocol CaseCountable: RawRepresentable {}
extension CaseCountable where RawValue == Int {
static var count: RawValue {
var i: RawValue = 0
while let _ = Self(rawValue: i) { i += 1 }
return i
}
}
Credits: Based on the answers by bzz and Nate Cook.
Generic IntegerType (in Swift 3 renamed to Integer) is not supported, as it's a heavily fragmented generic type which lacks a lot of functions. successor is not available with Swift 3 anymore.
Be aware that the comment from Code Commander to Nate Cooks answer is still valid:
While nice because you don't need to hardcode a value, this will
instantiate every enum value each time it is called. That is O(n)
instead of O(1).
As far as I know there is currently no workaround when using this as protocol extension (and not implementing in each enum like Nate Cook did) due to static stored properties not being supported in generic types.
Anyway, for small enums this should be no issue. A typical use case would be the section.count for UITableViews as already mentioned by Zorayr.
Extending Matthieu Riegler answer, this is a solution for Swift 3 that doesn't require the use of generics, and can be easily called using the enum type with EnumType.elementsCount:
extension RawRepresentable where Self: Hashable {
// Returns the number of elements in a RawRepresentable data structure
static var elementsCount: Int {
var i = 1
while (withUnsafePointer(to: &i, {
return $0.withMemoryRebound(to: self, capacity: 1, { return
$0.pointee })
}).hashValue != 0) {
i += 1
}
return i
}
I solved this problem for myself by creating a protocol (EnumIntArray) and a global utility function (enumIntArray) that make it very easy to add an "All" variable to any enum (using swift 1.2). The "all" variable will contain an array of all elements in the enum so you can use all.count for the count
It only works with enums that use raw values of type Int but perhaps it can provide some inspiration for other types.
It also addresses the "gap in numbering" and "excessive time to iterate" issues I've read above and elsewhere.
The idea is to add the EnumIntArray protocol to your enum and then define an "all" static variable by calling the enumIntArray function and provide it with the first element (and the last if there are gaps in the numbering).
Because the static variable is only initialized once, the overhead of going through all raw values only hits your program once.
example (without gaps) :
enum Animals:Int, EnumIntArray
{
case Cat=1, Dog, Rabbit, Chicken, Cow
static var all = enumIntArray(Animals.Cat)
}
example (with gaps) :
enum Animals:Int, EnumIntArray
{
case Cat = 1, Dog,
case Rabbit = 10, Chicken, Cow
static var all = enumIntArray(Animals.Cat, Animals.Cow)
}
Here's the code that implements it:
protocol EnumIntArray
{
init?(rawValue:Int)
var rawValue:Int { get }
}
func enumIntArray<T:EnumIntArray>(firstValue:T, _ lastValue:T? = nil) -> [T]
{
var result:[T] = []
var rawValue = firstValue.rawValue
while true
{
if let enumValue = T(rawValue:rawValue++)
{ result.append(enumValue) }
else if lastValue == nil
{ break }
if lastValue != nil
&& rawValue > lastValue!.rawValue
{ break }
}
return result
}
Or you can just define the _count outside the enum, and attach it statically:
let _count: Int = {
var max: Int = 0
while let _ = EnumName(rawValue: max) { max += 1 }
return max
}()
enum EnumName: Int {
case val0 = 0
case val1
static let count = _count
}
That way no matter how many enums you create, it'll only ever be created once.
(delete this answer if static does that)
The following method comes from CoreKit and is similar to the answers some others have suggested. This works with Swift 4.
public protocol EnumCollection: Hashable {
static func cases() -> AnySequence<Self>
static var allValues: [Self] { get }
}
public extension EnumCollection {
public static func cases() -> AnySequence<Self> {
return AnySequence { () -> AnyIterator<Self> in
var raw = 0
return AnyIterator {
let current: Self = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: self, capacity: 1) { $0.pointee } }
guard current.hashValue == raw else {
return nil
}
raw += 1
return current
}
}
}
public static var allValues: [Self] {
return Array(self.cases())
}
}
enum Weekdays: String, EnumCollection {
case sunday, monday, tuesday, wednesday, thursday, friday, saturday
}
Then you just need to just call Weekdays.allValues.count.
Just want to share a solution when you have an enum with associated values.
enum SomeEnum {
case one
case two(String)
case three(String, Int)
}
CaseIterable doesn't provide allCases automatically.
We can't provide a raw type like Int for your enum to calculate cases count somehow.
What we can do is to use power of switch and fallthrough keyword.
extension SomeEnum {
static var casesCount: Int {
var sum = 0
switch Self.one { // Potential problem
case one:
sum += 1
fallthrough
case two:
sum += 1
fallthrough
case three:
sum += 1
}
return sum
}
}
So now you can say SomeEnum.casesCount.
Remarks:
We still have a problem with switch Self.one {..., we hardcoded the first case. You can easily hack this solution. But I used it just for unit tests so that was not a problem.
If you often need to get cases count in enums with associated values, think about code generation.
struct HashableSequence<T: Hashable>: SequenceType {
func generate() -> AnyGenerator<T> {
var i = 0
return AnyGenerator {
let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory }
if next.hashValue == i {
i += 1
return next
}
return nil
}
}
}
extension Hashable {
static func enumCases() -> Array<Self> {
return Array(HashableSequence())
}
static var enumCount: Int {
return enumCases().enumCount
}
}
enum E {
case A
case B
case C
}
E.enumCases() // [A, B, C]
E.enumCount // 3
but be careful with usage on non-enum types. Some workaround could be:
struct HashableSequence<T: Hashable>: SequenceType {
func generate() -> AnyGenerator<T> {
var i = 0
return AnyGenerator {
guard sizeof(T) == 1 else {
return nil
}
let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory }
if next.hashValue == i {
i += 1
return next
}
return nil
}
}
}
extension Hashable {
static func enumCases() -> Array<Self> {
return Array(HashableSequence())
}
static var enumCount: Int {
return enumCases().count
}
}
enum E {
case A
case B
case C
}
Bool.enumCases() // [false, true]
Bool.enumCount // 2
String.enumCases() // []
String.enumCount // 0
Int.enumCases() // []
Int.enumCount // 0
E.enumCases() // [A, B, C]
E.enumCount // 4
It can use a static constant which contains the last value of the enumeration plus one.
enum Color : Int {
case Red, Orange, Yellow, Green, Cyan, Blue, Purple
static let count: Int = Color.Purple.rawValue + 1
func toUIColor() -> UIColor{
switch self {
case .Red:
return UIColor.redColor()
case .Orange:
return UIColor.orangeColor()
case .Yellow:
return UIColor.yellowColor()
case .Green:
return UIColor.greenColor()
case .Cyan:
return UIColor.cyanColor()
case .Blue:
return UIColor.blueColor()
case .Purple:
return UIColor.redColor()
}
}
}
This is minor, but I think a better O(1) solution would be the following (ONLY if your enum is Int starting at x, etc.):
enum Test : Int {
case ONE = 1
case TWO
case THREE
case FOUR // if you later need to add additional enums add above COUNT so COUNT is always the last enum value
case COUNT
static var count: Int { return Test.COUNT.rawValue } // note if your enum starts at 0, some other number, etc. you'll need to add on to the raw value the differential
}
The current selected answer I still believe is the best answer for all enums, unless you are working with Int then I recommend this solution.

Swift switch statement for matching substrings of a String

Im trying to ask for some values from a variable.
The variable is going to have the description of the weather and i want to ask for specific words in order to show different images (like a sun, rain or so)
The thing is i have code like this:
if self.descriptionWeather.description.rangeOfString("Clear") != nil
{
self.imageWeather.image = self.soleadoImage
}
if self.descriptionWeather.description.rangeOfString("rain") != nil
{
self.imageWeather.image = self.soleadoImage
}
if self.descriptionWeather.description.rangeOfString("broken clouds") != nil
{
self.imageWeather.image = self.nubladoImage
}
Because when i tried to add an "OR" condition xcode gives me some weird errors.
Is it possible to do a swich sentence with that? Or anyone knows how to do add an OR condition to the if clause?
I had a similar problem today and realized this question hasn't been updated since Swift 1! Here's how I solved it in Swift 4:
switch self.descriptionWeather.description {
case let str where str.contains("Clear"):
print("clear")
case let str where str.contains("rain"):
print("rain")
case let str where str.contains("broken clouds"):
print("broken clouds")
default:
break
}
Swift 5 Solution
func weatherImage(for identifier: String) -> UIImage? {
switch identifier {
case _ where identifier.contains("Clear"),
_ where identifier.contains("rain"):
return self.soleadoImage
case _ where identifier.contains("broken clouds"):
return self.nubladoImage
default: return nil
}
}
You can do this with a switch statement using value binding and a where clause. But convert the string to lowercase first!
var desc = "Going to be clear and bright tomorrow"
switch desc.lowercaseString as NSString {
case let x where x.rangeOfString("clear").length != 0:
println("clear")
case let x where x.rangeOfString("cloudy").length != 0:
println("cloudy")
default:
println("no match")
}
// prints "clear"
Swift language has two kinds of OR operators - the bitwise ones | (single vertical line), and the logical ones || (double vertical line). In this situation you need a logical OR:
if self.descriptionWeather.description.rangeOfString("Clear") != nil || self.descriptionWeather.description.rangeOfString("clear") != nil {
self.imageWeather.image = self.soleadoImage
}
Unlike Objective-C where you could get away with a bitwise OR in exchange for getting a slightly different run-time semantic, Swift requires a logical OR in the expression above.
If you do this a lot, you can implement a custom ~= operator that defines sub-string matching. It lends itself to this nice syntax:
switch "abcdefghi".substrings {
case "def": // calls `"def" ~= "abcdefghi".substrings`
print("Found substring: def")
case "some other potential substring":
print("Found \"some other potential substring\"")
default: print("No substring matches found")
}
Implementation:
import Foundation
public struct SubstringMatchSource {
private let wrapped: String
public init(wrapping wrapped: String) {
self.wrapped = wrapped
}
public func contains(_ substring: String) -> Bool {
return self.wrapped.contains(substring)
}
public static func ~= (substring: String, source: SubstringMatchSource) -> Bool {
return source.contains(substring)
}
}
extension String {
var substrings: SubstringMatchSource {
return SubstringMatchSource(wrapping: self)
}
}
I'd recommend using a dictionary instead, as a mapping between the substring you're searching for and the corresponding image:
func image(for weatherString: String) -> UIImage? {
let imageMapping = [
"Clear": self.soleadoImage,
"rain": self.soleadoImage,
"broken clouds": self.nubladoImage]
return imageMapping.first { weatherString.contains($0.key) }?.value
}
A dictionary gives you flexibility, adding new mappings is easy to do.
This link also describes overloading operator ~= which is actually used by the switch statement for matching cases to allow you to match regular expressions.

Resources