Skip to content →

Tag: enumerations

Modeling State with Associated Enums

Shortly after writing a recent post on enums with associated values, I came upon another use case for such: representing transitory app states.

Here is the scenario. I have an app that goes through an authentication process: attempting to authenticate, successfully authenticated, or failed to authenticate. Similarly, upon authentication, it goes through a second series of steps for data retrieval: requesting and receiving the data, data received, or retrieval failed. Finally, book-ending those two processes, the app has a ready state: either it is or it isn’t ready.

Here’s how I represent these states with associated enum values:

enum AppState {

  case Authentication(OperationState)
  case DataRetrieval(OperationState)
  case Ready(bool)

  enum OperationState {
    case Active
    case Success
    case Failure
  }

  static var state: AppState = .Ready(false)
}

First, AppState captures as case statements the two processes for authentication and data retrieval, and the ready state. The associated value for the processes is the nested OperationState enumeration that captures one of the three states of each of those processes: Active, Success, or Failure. The Ready state need only be represented as true or false. It is the static state property on line 13 that allows me to capture any of those mutually exclusive transitory state values for the app.

Now I can establish that app state and test it like so:

AppState.state = .Authentication(.Active)
AppState.state = .DataRetrieval(.Success)

// ...

switch AppState.state {
case .Authentication(let state):
  switch state {
  case .Active:
    break // stand by
  case .Success:
    break // proceed with data retrieval
  case .Failure:
    break // can't retrieve the data
  }
case .DataRetrieval(let state):
  if state == .Success {
    // refresh the table view
  }
case .Ready(let ready):
  if ready { //...
  }
}

There are two types of comparison here: a switch statement and an if statement. Actually, the if statement on line 17 won’t work out of the box. We first need to conform our AppState to the Equatable protocol (if you’re doing this in a playground, it must go above the AppState definition):

func ==(left: AppState, right: AppState) -> Bool {
  switch (left, right) {
  case (.Authentication(let l), .Authentication(let r)): return l == r
  case (.DataRetrieval(let l), .DataRetrieval(let r)): return l == r
  case (.Ready(let l), .Ready(let r)): return l == r
  default: return false
  }
}

enum AppState: Equatable {
  // The external func ==(left:right:) satisfies Equatable
}

The default case is necessary here because we’re not testing every combination of left and right AppStates; with out it, we’d have to be more explicit, adding these cases:

  case (.Ready, .Authentication): return false
  case (.Ready, .DataRetrieval): return false
  case (.Authentication, .Ready): return false
  case (.Authentication, .DataRetrieval): return false
  case (.DataRetrieval, .Ready): return false
  case (.DataRetrieval, .Authentication): return false

In those instances, we’d in effect be comparing apples and oranges, which are not equal; so we return false. And clearly, having a default return value of false in lieu of all those case statements is preferable.

That’s it! In this illustration I employed associated value enums to represent in a very clean, readable way a series of states that various operations of the app can be in.

In a follow-up post I extend this with a delegate pattern for making notifications when the app’s state changes.

Leave a Comment

Nested Enumerations as Dictionary Keys

Type of expression is ambiguous without more context.

This may be an error you have seen before. It apparently occurs in more than one circumstance, this being one example of such:

struct Foo {
  enum Bar {
    case Alpha
    case Beta
  }
}
var outer = [Foo.Bar: String]() // Error

There are three ways I found to get that enum to work as a dictionary key. The first is to use it within the enclosing type:

struct Foo {
  enum Bar {
    case Alpha
    case Beta
  }
  var inner = [Bar: String]()
}

That’s hardly a solution, however, if you need a dictionary outside the context of Foo. What’s more, this usage doesn’t align with the Swift Programming Language Guide‘s statement:

To use a nested type outside of its definition context, prefix its name with the name of the type it is nested within: let heartsSymbol = BlackjackCard.Suit.Hearts.rawValue.

The second workaround is to move the Bar enum outside of Foo:

enum Bar {
  case Alpha
  case Beta
}

var dict = [Bar: String]()

Unfortunately, this forces Bar to lose its Foo context, which is the Guide’s primary stated purpose for having nested types in the first place:

Enumerations are often created to support a specific class or structure’s functionality. Similarly, it can be convenient to define utility classes and structures purely for use within the context of a more complex type. To accomplish this, Swift enables you to define nested types, whereby you nest supporting enumerations, classes, and structures within the definition of the type they support.

The third workaround is less a workaround than a solution, and that is to use the full notation for a dictionary declaration:

struct Foo {
  enum Bar: String {
    case Alpha
    case Beta
  }
}
var outer = Dictionary<Foo.Bar, String>() // Works!

Why the abbreviated syntax leads to an ambiguous type reference remains unclear, but using the full syntax does the trick.

Leave a Comment

Duplicate XML Elements and Associated Enum Values

This is the third in a series of articles on parsing an online XML document. In the previous post, Parsing an XML Document, I focused on how to use NSXMLParser and NSXMLParserDelegate to assist in parsing, but left a bit of unfinished business: capturing the hierarchy of the document. This is something NSXMLParser and its delegate methods do not do. I was planning to address the entirety of a solution here, but a bit of other (but related) business intervened.

For now, I look at a few approaches to representing a collection of child elements within the XMLElement I have been building so far, and will further build upon the chosen approach in the next article to discuss actual construction of the XML tree object.

Common to all approaches is for each XMLElement to have a collection of child XMLElements. This makes sense because every child of an XML element is itself an XML element.

Unfortunately, things are complicated by the fact that not all element names are unique within a given collection of elements. Consider this excerpt that expounds upon the XML document example introduced in the first article, which did not show any keywords:

<KeywordList>
  <Keyword>WCS</Keyword>
  <Keyword>GeoTIFF</Keyword>
  <Keyword>AerialOK_SP_LL84_HalfFoot_5-7-2015></Keyword>
</KeywordList>

This is relevant because if we are to want to store child elements in a dictionary (presumably by their name) so that we can easily reference them, duplicate names would be prohibitive. We could store child elements for all element types within an array, but then we lose the inherent ability to reference them by name that a dictionary provides.

The first solution to addressing the duplicate element names is to store XMLElement child elements in an array within a dictionary, like so (this adds to the XMLElement class defined so far in this series):

class XMLElement { // excerpt

  /// Stores an array of one or more child elements for a given element name.
  var elements: [String: [XMLElement]] = [:]

  /**
   Adds an `element` with `name` to the collection of child `elements`.
   */
  func addElement(element: XMLElement, withName name: String) {

    // First element with this name, create elements array
    if elements[name] == nil {
      elements[name] = [XMLElement]()
    }

    // Add element to dictionary array
    elements[name]!.append(element)
  }

  /**
   Returns the first child element from `elements` with `name`.
   */
  func firstElementWithName(name: String) -&gt; XMLElement? {
    return elements[name]?[0]
  }
}

I provide firstElementWithName(_:) on line 23 for illustration. To return all the elements with a particular name is simply a matter of directly querying elements. Determining which element in the array you need after that point is really up to how the XML is being utilized, and I don’t address that here.

This approach does have the benefit of simplicity. However, I do not like that those elements appearing only once are stored in an array…an array with only one element. So I sought a native Swift solution that might let me, in effect, return either a single XMLElement or an array of XMLElements.

In the below excerpt (which replaces the prior one), a data structure like that given on line 4 would eliminate the explicit array, where Any can now be an XMLElement or an array of XMLElements.

class XMLElement { // excerpt

  /// Dictionary of `XMLElement` or `XMLElement` arrays, keyed on element name.
  private(set) var elements: [String: Any] = [:]

  /** 
   Adds an element to an array of child `XMLElement`s.
   */
  func addElement(element: XMLElement, withName name: String) {

    // Add to a single element
    if let existingElement = elements["Name"] as? XMLElement {
      elements["Name"] = [existingElement, element]
    }

    // Add to an array of elements
    else if var elementsWithName = elements["Name"] as? [XMLElement] {
      elementsWithName.append(element)
      elements["Name"] = elementsWithName
    }

    // Add the first single
    else {
      elements["Name"] = element
    }
  }

  /**
   Returns the first of the named `XMLElement` array, 
   or `nil` if no such named elements exist.
   */
  func firstElementWithName(name: String) -&gt; Any? {

    // A single element
    if let element = elements["Name"] as? XMLElement {
      return element
    }

    // An array of elements
    else if let elements = elements["Name"] as? [XMLElement] {
      return elements[0]
    }

    // No element with this name
    return nil
  } 
}

This is considerably more complex than the former approach, but while it has the benefit of eliminating the array for single XMLElement values with a specific name, it gains some type ambiguity. The private setter on line 4 mitigates any mis-assignments to the elements dictionary, but the return value on firstElementWithName(_:) is not an explicit XMLElement or [XMLElement]. This may be good solution, but I sought something better.

The last approach I discuss came from me exploring how I could return or represent in Swift an either/or value…without opening it up to Any. What came to mind was my prior reading on associated enumuration values. I had yet to have the opportunity to use those, and this application for them seemed to have potential.

class XMLElement { // excerpt

  /**
   Restricts the valid forms a child `XMLElement` can take: 
   a single element or a collection of them.
   */
  enum XMLElements {
    case Single(XMLElement)
    case Collection([XMLElement])
  }

  /// Dictionary of `XMLElements`, keyed on element name.
  var elements: [String: XMLElements] = [:]

  /**
   Adds an element to an dictionary of child `XMLElements`.
   */
  func addElement(element: XMLElement, withName name: String) {

    // Sibling elements with same name
    if let elementsForName = elements[name] {
      switch elementsForName {

      // Create collection
      case .Single(let existingElement):
        elements[name] = .Collection([existingElement, element])

      // Add to collection
      case .Collection(var existingElements):
        existingElements.append(element)
        elements[name] = .Collection(existingElements)
      }
    }

    // First element with this name
    else {
      elements[name] = .Single(element)
    }
  }

  /**
   Returns the first named child `XMLElement`, or `nil` if no such element exists.
   */
  func firstElementWithName(name: String) -> XMLElement? {

    if let elements = elements[name] {
      switch elements {

      case .Single(let element):
        return element

      case .Collection(let elements):
        return elements[0]
      }
    }

    // No elements with this name
    else {
      return nil
    }
  }
}

This is very similar to the preceding Any approach, in that it avoids storing an array of XMLElements for every element, but it has the benefit of strong typing and being a bit more self-documenting. While it does have the greatest complexity of the three approaches, we can know with certainty the elements property of an XMLElement will contain nothing but XMLElements, if anything at all, and the return value from firstElementWithName(_:) is non-ambiguous.

I will press ahead with that implementation in the fourth installment in this series where I use it to build a document tree object.

Leave a Comment