Iterating through an Enum in Swift 3.0 - swift

I have a simple enum that I would like to iterate over. For this purpose, I've adopted Sequence and IteratorProtocol as shown in the code below. BTW, this can be copy/pasted to a Playground in Xcode 8.
import UIKit
enum Sections: Int {
case Section0 = 0
case Section1
case Section2
}
extension Sections : Sequence {
func makeIterator() -> SectionsGenerator {
return SectionsGenerator()
}
struct SectionsGenerator: IteratorProtocol {
var currentSection = 0
mutating func next() -> Sections? {
guard let item = Sections(rawValue:currentSection) else {
return nil
}
currentSection += 1
return item
}
}
}
for section in Sections {
print(section)
}
But the for-in loop generates the error message "Type 'Sections.Type' does not conform to protocol 'Sequence'".
The protocol conformance is in my extension; so, what is wrong with this code?
I know there are other ways of doing this but I'd like to understand what's wrong with this approach.
Thanks.

Note that Martin’s solution can be refactored as a protocol:
import Foundation
protocol EnumSequence
{
associatedtype T: RawRepresentable where T.RawValue == Int
static func all() -> AnySequence<T>
}
extension EnumSequence
{
static func all() -> AnySequence<T> {
return AnySequence { return EnumGenerator() }
}
}
private struct EnumGenerator<T: RawRepresentable>: IteratorProtocol where T.RawValue == Int {
var index = 0
mutating func next() -> T? {
guard let item = T(rawValue: index) else {
return nil
}
index += 1
return item
}
}
Then, given an enum
enum Fruits: Int {
case apple, orange, pear
}
you slap the protocol and a typealias:
enum Fruits: Int, EnumSequence {
typealias T = Fruits
case apple, orange, pear
}
Fruits.all().forEach({ print($0) }) // apple orange pear

Update: As of Swift 4.2, you can simply add protocol conformance
to CaseIterable, see How to enumerate an enum with String type?.
You can iterate over a value of a type which conforms to the Sequence
protocol. Therefore
for section in Sections.Section0 {
print(section)
}
would compile and give the expected result. But of course that is not
really what you want because the choice of the value is arbitrary and the
value itself not needed in the sequence.
As far as I know, there is no way to iterate over a type itself, so that
for section in Sections {
print(section)
}
compiles. That would require that the "metatype" Sections.Type conforms
to Sequence. Perhaps someone proves me wrong.
What you can do is to define a type method which returns a sequence:
extension Sections {
static func all() -> AnySequence<Sections> {
return AnySequence {
return SectionsGenerator()
}
}
struct SectionsGenerator: IteratorProtocol {
var currentSection = 0
mutating func next() -> Sections? {
guard let item = Sections(rawValue:currentSection) else {
return nil
}
currentSection += 1
return item
}
}
}
for section in Sections.all() {
print(section)
}

Simply add to enum:
static var allTypes: [Sections] = [.Section0, .Section1, .Section2]
And than you can:
Sections.allTypes.forEach { (section) in
print("\(section)")
}

This looks so much simpler:
public protocol EnumSequence {
init?(rawValue: Int)
}
public extension EnumSequence {
public static var items: [Self] {
var caseIndex: Int = 0
let interator: AnyIterator<Self> = AnyIterator {
let result = Self(rawValue: caseIndex)
caseIndex += 1
return result
}
return Array(interator)
}
}

Iterated upon the solutions above, see below a protocol that can be implemented by enumerations to add the allValues sequence but also to allow the possibility to convert to and from string value.
Very convenient for String-like enumerations which need to support objective c (only int enumerations are allowed there).
public protocol ObjcEnumeration: LosslessStringConvertible, RawRepresentable where RawValue == Int {
static var allValues: AnySequence<Self> { get }
}
public extension ObjcEnumeration {
public static var allValues: AnySequence<Self> {
return AnySequence {
return IntegerEnumIterator()
}
}
public init?(_ description: String) {
guard let enumValue = Self.allValues.first(where: { $0.description == description }) else {
return nil
}
self.init(rawValue: enumValue.rawValue)
}
public var description: String {
return String(describing: self)
}
}
fileprivate struct IntegerEnumIterator<T: RawRepresentable>: IteratorProtocol where T.RawValue == Int {
private var index = 0
mutating func next() -> T? {
defer {
index += 1
}
return T(rawValue: index)
}
}
For a concrete example:
#objc
enum Fruit: Int, ObjcEnumeration {
case apple, orange, pear
}
Now you can do:
for fruit in Fruit.allValues {
//Prints: "apple", "orange", "pear"
print("Fruit: \(fruit.description)")
if let otherFruit = Fruit(fruit.description), fruit == otherFruit {
print("Fruit could be constructed successfully from its description!")
}
}

If your enum is an Int based one, you can do an effective but slightly dirty trick like this.
enum MyEnum: Int {
case One
case Two
}
extension MyEnum {
func static allCases() -> [MyEnum] {
var allCases = [MyEnum]()
for i in 0..<10000 {
if let type = MyEnum(rawValue: i) {
allCases.append(type)
} else {
break
}
}
return allCases
}
}
Then loop over MyEnum.allCases()..

Related

WeakBox requires that WeakArray<Element>.Element be a class type

I'm trying to implement a storing weak references solutions from objc talks (https://www.objc.io/blog/2017/12/28/weak-arrays/) but I'm not able to get it working.
The exact error message tells:
'WeakBox' requires that 'WeakArray<Element>.Element' (aka 'Optional<Element>') be a class type
With this code:
final class WeakBox<A: AnyObject> {
weak var unbox: A?
init(_ value: A) {
unbox = value
}
}
struct WeakArray<Element: AnyObject> {
private var items: [WeakBox<Element>] = []
init(_ elements: [Element]) {
items = elements.map { WeakBox($0) }
}
init() {}
}
extension WeakArray: Collection {
var startIndex: Int { return items.startIndex }
var endIndex: Int { return items.endIndex }
subscript(_ index: Int) -> Element? {
return items[index].unbox
}
func index(after idx: Int) -> Int {
return items.index(after: idx)
}
mutating func append(_ element: Element) {
items.append(WeakBox(element))
}
mutating func removeAll() {
items.removeAll()
}
}
**
Update:
**
After some time I realized that error message is completely misleading. The real problem is in calling methods of a Sequence protocol. For example, adding something like this below produces an error message from the above screenshot. But I haven't found a solution yet.
class De {
let de = "de"
}
let de = De()
var ar = WeakArray<De>([])
ar.append(de)
ar.append(de)
ar.forEach({ $0 })
I believe 'Element' is being redefined by the SDK somewhere. Renaming Element to T should fix the issue.
import Foundation
final class WeakBox<T:AnyObject> {
weak var unbox: T?
init(_ value: T?) {
unbox = value
}
}
struct WeakArray<T: AnyObject> {
private var items: [WeakBox<T>] = []
init(_ elements: [T]) {
items = elements.map { WeakBox($0) }
}
init(_ elements: [T?]) {
items = elements.map { WeakBox($0) }
}
mutating func append(_ obj:T?) {
items.append(WeakBox(obj))
}
mutating func remove(at:Int) {
items.remove(at: at)
}
}
extension WeakArray: Collection {
var startIndex: Int { return items.startIndex }
var endIndex: Int { return items.endIndex }
subscript(_ index: Int) -> T? {
return items[index].unbox
}
func index(after idx: Int) -> Int {
return items.index(after: idx)
}
}

Extending a Collection where the Element type is generic (Swift)

It's simple to extend a Collection type in swift to have a custom function for particular Element types:
struct MyStruct {
let string: String
}
extension Set where Element == MyStruct {
func getFirstWith(string: String) -> Element? {
return filter({ $0.string == string }).first
}
}
But suppose your Element type is generic?
protocol MyProtocol {}
struct MyGenericStruct<T: MyProtocol> {
let string: String
}
// error on next line:
// error: expected '>' to complete generic argument list
// extension Set where Element == MyGenericStruct<T: MyProtocol> {
// ^
extension Set where Element == MyGenericStruct<T: MyProtocol> {
func getFirstWith(string: String) -> Element? {
return filter({ $0.string == string }).first
}
}
// error on next line:
// error: use of undeclared type 'T'
// extension Set where Element == MyGenericStruct<T> {
// ^
extension Set where Element == MyGenericStruct<T> {
func getFirstWith(string: String) -> Element? {
return filter({ $0.string == string }).first
}
}
It's unclear to me how to declare that my element is a generic.
Details
Swift 3.1, xCode 8.3.3
Solution
import Foundation
struct MyStruct:Hashable {
let string: String
static func == (lhs: MyStruct, rhs: MyStruct) -> Bool {
return lhs.string == rhs.string
}
var hashValue: Int {
return string.hash
}
}
extension Set where Element == MyStruct {
func getFirstWith(string: String) -> Element? {
return filter({ $0.string == string }).first
}
}
var set = Set<MyStruct>()
set.insert(MyStruct(string: "123"))
set.insert(MyStruct(string: "231"))
print(String(describing:set.getFirstWith(string: "123")))
print(String(describing:set.getFirstWith(string: "231")))
///////////////////////////////////
protocol MyProtocol {}
struct MyType1: MyProtocol {}
struct MyType2: MyProtocol {}
struct MyGenericStruct<T: MyProtocol>: Hashable {
let string: String
static func == (lhs: MyGenericStruct, rhs: MyGenericStruct) -> Bool {
return lhs.string == rhs.string
}
var hashValue: Int {
return string.hash
}
}
extension Set where Element == AnyHashable {
func getFirstWith(string: String) -> Element? {
return filter{ element -> Bool in
if let _element = element as? MyGenericStruct<MyType1> {
if _element.string == string {
return true
}
}
if let _element = element as? MyGenericStruct<MyType2> {
if _element.string == string {
return true
}
}
return false
}.first
}
}
var set2 = Set<AnyHashable>()
set2.insert(MyGenericStruct<MyType1>(string: "abc"))
set2.insert(MyGenericStruct<MyType2>(string: "cba"))
print(String(describing: set2.getFirstWith(string: "abc")))
print(String(describing:set2.getFirstWith(string: "cba")))
Result
Answering my own question here on request.
I was unable to figure out how to make this an extension on Set.
Instead, we wrote a little utility function. Not as clear as a extension, but gets the work done. It looks like this:
func getFirst<T: MyProtocol>(fromSet set: Set<MyGenericStruct<T>>, whereStringIs string: String) -> MyGenericStruct<T>? {
return set.first(where: { $0.string == string })
}
As others have noted, MyGenericStruct needs to be Hashable.
If I do understand the purpose, you probably need to have more implementation in your protocol and structure.
First, element's protocol has to be hashable and equitable.
protocol MyProtocol: Hashable, Equatable {
var string: String { get }
}
Therefore, MyGenericStruct will look like the following.
struct MyGenericStruct: MyProtocol {
let string: String
var hashValue: Int {
get {
return string.hashValue
}
}
static func ==(lhs: MyGenericStruct, rhs: MyGenericStruct) -> Bool {
return lhs.hashValue == rhs.hashValue
}
}
Then, declare extension with constraints specified by a where clause for MyProtocol
extension Set where Element: MyProtocol {
func getFirstWith(string: String) -> Element? {
return filter({$0.string == string}).first
}
}
Finally, let's do a test and see its result.
// Example
let set: Set = [
MyGenericStruct(string: "Watermelon"),
MyGenericStruct(string: "Orange"),
MyGenericStruct(string: "Banana")
]
let output = set.getFirstWith(string: "Orange")
print(output)
In my playground with Xcode 8, I can get Optional(MyGenericStruct(string: "Orange")) in log.
[UPDATED1] To make an Extension on Set<MyGenericStruct> only:
extension Set where Element == MyGenericStruct {
func getFirstWith(string: String) -> Element? {
return filter({$0.string == string}).first
}
}
[UPDATED2] In case to keep MyGenericStruct<T: MyProtocol> declaration as stated is necessary, another approach to implement Set extension:
protocol MyProtocol {
}
struct BaseStruct1: MyProtocol {
}
struct BaseStruct2: MyProtocol {
}
protocol ContainStringProtocol: Hashable {
var string: String { get }
}
struct MyGenericStruct<T: MyProtocol>: ContainStringProtocol {
var string: String
var hashValue: Int {
get {
return string.hashValue
}
}
init(string: String) {
self.string = string
}
static func ==(lhs: MyGenericStruct, rhs: MyGenericStruct) -> Bool {
return lhs.hashValue == rhs.hashValue
}
}
extension Set where Element: ContainStringProtocol {
func getFirstWith(string: String) -> Element? {
return filter({$0.string == string}).first
}
}
// Example
let set1: Set = [
MyGenericStruct<BaseStruct1>(string: "Watermelon"),
MyGenericStruct<BaseStruct1>(string: "Orange"),
MyGenericStruct<BaseStruct1>(string: "Banana")
]
let output1 = set1.getFirstWith(string: "Orange")
print(output1!)
let set2: Set = [
MyGenericStruct<BaseStruct2>(string: "Watermelon"),
MyGenericStruct<BaseStruct2>(string: "Orange"),
MyGenericStruct<BaseStruct2>(string: "Banana")
]
let output2 = set2.getFirstWith(string: "Orange")
print(output2!)

Class extension typealias's property type constraint

Mission: I need to provide an Array extension method which would compare 2 arrays of raw representables whose raw type conforms to Equatable and say if the arrays contain the same elements by reusing the below pieces of code.
What I have at the moment:
public extension Array {
func containsTheSameElements(as array: [Element], condition: #escaping (Element, Element) -> Bool) -> Bool {
var localCopy = array
let countOfUncommonElements = reduce(0) { (uncommonElementsCount: Int, item: Element) -> Int in
if let index = localCopy.index(where: {condition(item, $0)}) {
localCopy.remove(at: index)
return uncommonElementsCount
} else {
return uncommonElementsCount + 1
}
}
return countOfUncommonElements == 0 && count == array.count
}
}
func enumComparisonClosure<T: RawRepresentable>(firstItem: T, secondItem: T) -> Bool where T.RawValue: Equatable {
return firstItem == secondItem
}
How I'm using it at the moment:
class Somewhere {
enum EnumType: String {
case first
case second
}
func method() {
let firstArray: [EnumType] = [.first, .second]
let secondArray: [EnumType] = [.second]
firstArray.containsTheSameElements(as: secondArray, condition: enumComparisonClosure)
}
}
How I would like to use it:
firstArray.containsTheSameElements(as: secondArray)
How I would like to be able to implement it:
public extension Array {
func containsTheSameElements<Element: RawRepresentable>(as array: [Element]) -> Bool where Element.RawValue: Equatable {
return containsTheSameElements(as: array, condition: enumComparisonClosure)
}
}
How can I constrain the Array's extension "Element" typealias to be a RawRepresentable with RawValue of Equatable type?
Or what would be another approach to make this comparison possible?
The constraints on the extension are separated by a comma, not
by &. The containsTheSameElements must take a [T] argument
where T is a RawRepresentable with the same RawValue
as the array elements.
Example:
extension Array where Element: RawRepresentable, Element.RawValue: Equatable {
func containsTheSameElements<T>(as array: [T]) -> Bool
where T: RawRepresentable, T.RawValue == Element.RawValue
{
return self.count == array.count &&
!zip(self, array).contains { $0.rawValue != $1.rawValue }
}
}
Update: It is simpler if you need it only for arrays
of the same type:
extension Array where Element: RawRepresentable, Element.RawValue: Equatable {
func containsTheSameElements(as array: [Element]) -> Bool
{
return self.count == array.count &&
!zip(self, array).contains { $0.rawValue != $1.rawValue }
}
}
or, reusing your existing method:
extension Array where Element: RawRepresentable, Element.RawValue: Equatable {
func containsTheSameElements(as array: [Element]) -> Bool
{
return containsTheSameElements(as: array, condition: enumComparisonClosure)
}
}

protocol type constraint by two protocols

I've setup two protocols below in swift 2
Generative (for the lack of a better name) which holds an array of items and provides Datasource like functionality like count and subscript
public protocol Generative {
typealias GeneratedType
var elements: [GeneratedType] { get }
}
public extension Generative {
func count() -> Int {
return elements.count
}
subscript(index:Int) -> GeneratedType? {
if index >= count() {
return nil
}
return elements[index]
}
}
public protocol Selectable {
typealias SelectableType: Hashable
var selectedElements: Set<SelectableType> { get set }
}
extension Selectable {
public func isSelected(elem: SelectableType) -> Bool {
return selectedElements.contains(elem)
}
public mutating func addSelection(elem: SelectableType) {
selectedElements.insert(elem)
}
public mutating func removeSelection(elem: SelectableType) {
selectedElements.remove(elem)
}
public mutating func clearSelections() {
selectedElements.removeAll()
}
}
So in case an object implements both Generative and Selectable then I want it to be able to return the selected indices so I wrote this function:
func selectedIndices<S: Selectable where S: Generative, S.GeneratedType == S.SelectableType>(ds: S) -> [NSIndexPath] {
var selections: [NSIndexPath] {
return ds.selectedElements
.map{ (p: S.GeneratedType) -> NSIndexPath? in
if let idx = ds.elements.indexOf(p) { idx
return NSIndexPath(forRow: idx, inSection: 0)
}
return nil
}
.filter{ $0 != nil }
.map{ $0! }
}
return selections
}
for some reason the linker prints out:
Command failed due to signal: Segmentation fault: 11
Not sure why is that, I can't figure out another way to specify this function to work on objects which implement both protocols and their associated types match...
Any ideas ?
P.S. the code in a Gist: https://gist.github.com/edwardIshaq/715b0e134fb47d2e28cc
------- UPDATE
removing the computed property seemed to do the trick :
func selectedIndices<S: Selectable where S: Generative, S.GeneratedType == S.SelectableType>(ds: S) -> [NSIndexPath] {
return ds.selectedElements
.flatMap { (p: S.GeneratedType) -> NSIndexPath? in
if let idx = ds.elements.indexOf(p) { idx
return NSIndexPath(forRow: idx, inSection: 0)
}
return nil
}
}
The compiler should never crash, but it looks like the cause is simpler, seems to be to do with generic functions that use computed properties internally, this is as simple as I can get it:
// swiftc crashes when compiling this
func f<T>(t: T) -> Int {
var v: Int {
return 0
}
return v
}
so as a workaround, try refactoring the code to not use the computed property.
You could do that, and write this as an extension of the two protocols, like this:
extension Selectable
where Self: Generative,
Self.GeneratedType == NSIndexPath,
Self.SelectableType == NSIndexPath
{
func selectedIndices() -> [NSIndexPath] {
return self.selectedElements.flatMap {
self.elements.indexOf($0).map { NSIndexPath(index: $0) }
}
}
}

How to make an enum conform to a protocol in Swift?

Swift documentation says that classes, structs, and enums can all conform to protocols, and I can get to a point where they all conform. But I can't get the enum to behave quite like the class and struct examples:
protocol ExampleProtocol {
var simpleDescription: String { get set }
mutating func adjust()
}
class SimpleClass: ExampleProtocol {
var simpleDescription: String = "A very simple class."
var anotherProperty: Int = 69105
func adjust() {
simpleDescription += " Now 100% adjusted."
}
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription
struct SimpleStructure: ExampleProtocol {
var simpleDescription: String = "A simple structure"
mutating func adjust() {
simpleDescription += " (adjusted)"
}
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription
enum SimpleEnum: ExampleProtocol {
case Base
var simpleDescription: String {
get {
return "A Simple Enum"
}
set {
newValue
}
}
mutating func adjust() {
self.simpleDescription += ", adjusted"
}
}
var c = SimpleEnum.Base
c.adjust()
let cDescription = c.simpleDescription
I haven't figured out how to get the simpleDescription to change as a result of calling adjust(). My example obviously won't do that because the getter has a value hard-coded, but how can I set a value for the simpleDescription while still conforming to the ExampleProtocol?
This is my attempt:
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
enum ExampleEnum : ExampleProtocol {
case Base, Adjusted
var simpleDescription: String {
return self.getDescription()
}
func getDescription() -> String {
switch self {
case .Base:
return "A simple description of enum"
case .Adjusted:
return "Adjusted description of enum"
}
}
mutating func adjust() {
self = ExampleEnum.Adjusted
}
}
var c = ExampleEnum.Base
c.adjust()
let cDescription = c.simpleDescription
Here is my take at it.
As this is an enum and not a class, you have to think different(TM): it is your description that has to change when the "state" of your enum changes (as pointed out by #hu-qiang).
enum SimpleEnumeration: ExampleProtocol {
case Basic, Adjusted
var description: String {
switch self {
case .Basic:
return "A simple Enumeration"
case .Adjusted:
return "A simple Enumeration [adjusted]"
}
}
mutating func adjust() {
self = .Adjusted
}
}
var c = SimpleEnumeration.Basic
c.description
c.adjust()
c.description
Hope that helps.
Here's another approach, using only the knowledge gained from the tour until that point*
enum SimpleEnumeration: String, ExampleProtocol {
case Basic = "A simple enumeration", Adjusted = "A simple enumeration (adjusted)"
var simpleDescription: String {
get {
return self.toRaw()
}
}
mutating func adjust() {
self = .Adjusted
}
}
var c = SimpleEnumeration.Basic
c.adjust()
let cDescription = c.simpleDescription
If you want to have adjust() act as a toggle (although there's nothing to suggest this is the case), use:
mutating func adjust() {
switch self {
case .Basic:
self = .Adjusted
default:
self = .Basic
}
}
*(Although it doesn't explicitly mention how to specify a return type and a protocol)
Here's a solution that doesn't change the current enum value, but their instance values instead (just in case it is useful to anyone).
enum ProtoEnumeration : ExampleProtocol {
case One(String)
case Two(String)
var simpleDescription: String {
get {
switch self {
case let .One(desc):
return desc
case let .Two(desc):
return desc
}
}
}
mutating func adjust() {
switch self {
case let .One(desc):
self = .One(desc + ", adjusted 1")
case let .Two(desc):
self = .Two(desc + ", adjusted 2")
}
}
}
var p = ProtoEnumeration.One("test")
p.simpleDescription
p.adjust()
p.simpleDescription
It is not possible to define variables without getter and setter in enums and therefore it is impossible to have a variable that you can modify.
You can conform to the protocol but you cannot have same behavior with mutating as in classes.
It is a link about enum in swift.
Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods. link
Then, you have to use mutating function.
enum ProtocolEnum: ExampleProtocol {
case on, off
var simpleDescription: String {
switch self {
case .on:
return "Switch is ON"
case .off:
return "Switch is OFF"
}
}
mutating func adjust() {
switch self {
case .on:
self = off
case .off:
self = on
}
}
}
var c = ProtocolEnum.on
c.simpleDescription
c.adjust()
let cDescription = c.simpleDescription
Another option is for adjust() to flip between cases as follows:
enum SimpleEnum: ExampleProtocol {
case Foo, Bar
var simpleDescription: String {
get {
let value = self == .Foo
? "Foo"
: "Bar"
return "A simple \(value) enum."
}
}
mutating func adjust() {
self = self == .Foo
? .Bar
: .Foo
}
}
Here's building on Jack's answer:
protocol ICanWalk {
var description: String { get }
mutating func stepIt()
}
enum TwoStepsForwardThreeStepsBack: Int, ICanWalk {
case Base = 0, Step1, Step2
var description: String {
return "Step \(self.rawValue)"
}
mutating func stepIt() {
if let nextStep = TwoStepsForwardThreeStepsBack( rawValue: self.rawValue + 1 ) {
// going forward.
self = nextStep
} else {
// back to the base.
self = TwoStepsForwardThreeStepsBack.Base
}
}
}
I came up with this
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
enum Seat: ExampleProtocol {
case WindowSeat, MiddleSeat, AisleSeat
var simpleDescription : String {
switch self {
case .WindowSeat:
return "Window Seat"
case .MiddleSeat:
return "Middle Seat"
case .AisleSeat:
return "Aisle Seat"
}
}
mutating func adjust() {
switch self {
case .WindowSeat:
self = .MiddleSeat
case .MiddleSeat:
self = . AisleSeat
case .AisleSeat:
self = .WindowSeat
}
}
}
var seat = Seat.MiddleSeat
print(seat.simpleDescription) // Middle Seat
seat.adjust()
print(seat.simpleDescription) // Aisle Seat
Another variation: Using associated values to hold and display previous option
(of the form "Selected 1, adjusted from 2, adjusted from 1, adjusted from 2, adjusted from 1")
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
indirect enum EnumWithDescription: ExampleProtocol {
case option1(EnumWithDescription?)
case option2(EnumWithDescription?)
var simpleDescription: String {
return "Selected " + getDescription()
}
internal func getDescription() -> String {
var currentValue: String
let previousValue : EnumWithDescription?
switch self {
case .option1(let previous):
currentValue = "1"
previousValue = previous
case .option2(let previous):
currentValue = "2"
previousValue = previous
}
if let adjustedFrom = previousValue?.getDescription() {
return "\(currentValue) adjusted from \(adjustedFrom)"
}
else {
return "\(currentValue)"
}
}
mutating func adjust() {
switch self {
case .option1:
self = .option2(self)
case .option2:
self = .option1(self)
}
}
}
var d = EnumWithDescription.option1(nil)
d.simpleDescription
d.adjust()
d.adjust()
d.simpleDescription
// Output: "Selected 1, adjusted from 2, adjusted from 1, adjusted from 2, adjusted from 1"
here's my code
enum SimpleEnum: ExampleProtocol {
case Base, Adjusted
var simpleDescription: String {
get {
var description = "A simple enum."
switch self {
case .Base:
return description
case .Adjusted:
return description + " - [adjusted]"
}
}
}
mutating func adjust() {
self = SimpleEnum.Adjusted
}
}
var simpleEnum = SimpleEnum.Base
simpleEnum.adjust()
simpleEnum.simpleDescription
My first contribution here:
enum SimpleEnum: ExampleProtocol {
case Basic(String), Adjusted(String)
init() {
self = SimpleEnum.Basic("A simple Enum")
}
var simpleDescription: String {
get {
switch self {
case let .Basic(string):
return string
case let .Adjusted(string):
return string
}
}
}
mutating func adjust() {
self = SimpleEnum.Adjusted("full adjusted")
}
}
var c = SimpleEnum()
c.adjust()
let cDescription = c.simpleDescription
Thanks for others!
This experiment threw me off too, due to the previous SimpleClass and SimpleStructure examples showing the property simpleDescription being modified internally, which caused me to think that I needed to do the same thing. After looking over the other answers posted here and reading the official Apple Swift 2.1 documentation, I came up with this:
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
enum SimpleEnum: ExampleProtocol {
case Simple
case Adjusted
var simpleDescription: String {
switch self {
case .Simple:
return "A simple enumeration"
case .Adjusted:
return "A simple enumeration somewhat changed."
}
}
mutating func adjust() {
self = .Adjusted
}
mutating func restore() {
self = .Simple
}
}
var d: SimpleEnum = .Simple
d.simpleDescription
d.adjust()
d.simpleDescription
d.restore()
d.simpleDescription
Also notice that in the examples given by Apple for SimpleClass and SimpleStructure prior to this experiment, the simple description is lost internally - you cannot get the original value back (unless of course you save it outside of the class/structure); this is what prompted me to create a restore() method for the SimpleEnum example, which allows you to toggle it back and forth between values. Hope this is useful to someone!
I was thinking that the goal is simply to retain state and use a description to make the current state easier to read:
enum SimpleEnum: ExampleProtocol {
case Default, Adjusted
init() {
self = .Default
}
var simpleDescription: String { get { return "\(self) Value" }}
mutating func adjust() {
self = .Adjusted
}
}
var simpleEnum = SimpleEnum()
simpleEnum.adjust()
let adjustedSimple = simpleEnum.simpleDescript
how about this
enum SimpleEnum : ExampleProtocol {
case Desc(String)
init() {
self = Desc("a simple enum")
}
var simpleDescription:String {
get {
return (Mirror(reflecting: self).children.first!.value as? String)!
}
}
mutating func adjust() {
self = SimpleEnum.Desc(self.desc + " adjusted")
}
}
var e = SimpleEnum()
e.simpleDescription # => "a simple enum"
e.adjust()
e.simpleDescription # => "a simple enum adjusted"