Swift Enums in Objective C

Using a Swift Integer enum in Objective C (the only Swift enum type that can be used in Objective C) is problematic. A public Objective C property for the enum can't be created directly. Consider:

// In a Swift file
enum StringStyle: Int {
    case none
    case bold
    case italic
}

// In an Objective C header file
// The Swift header cannot be imported in an Objective C header file...
#import "Project-Swift.h" // Can't do this

@interface MyClass: NSObject {
    // ...so a property of the enum type cannot be declared
    // because the enum type is not visible here without the Swift.h import
    @property (nonatomic, assign) StringStyle style; // Can't do this
}

One work around is to declare an NSInteger in the Objective C header file as a stand in for the enum type instead:

// In an Objective C header file
@property (nonatomic, assign) NSInteger style;

Unfortunately, any function that moves the NSInteger/enum between Swift and Objective C code will require conversion between the Objective C NSInteger and the Swift enum type.

This is a pain.

However, the effect of a public Swift enum property in Objective C code can still be achieved. The conversion between an NSInteger and the Swift enum can be centralized, thereby simplifying all bridging code between Objective C and Swift. This solution works through a Swift extension on the Objective C class that provides the enum property.

Ah, but a new property can't be declared through an extension! This is true, but easily worked around.

A computed property can be declared that creates an associated object as the backing store for the property. It will appear to be a public property of the Objective C class and of the enum type. Client code will not need to perform conversions between NSInteger and Swift enum representations since client code will only see a Swift enum type, as it should. The enum values can be used directly within and passed between both Objective C and Swift code. Here is an example of the computed property in an extension of the Objective C class:

extension MyClass {
    // Create a key to reference the associated object
    private struct Key {
        static var style = "StringStyle"
    }
    
    // This will appear as a public property on instances of the Objective C class
    @objc var style: StringStyle {
    	get {
            guard
                let value = objc_getAssociatedObject(self, &Key.style) as? NSNumber,
                let style = StringStyle(rawValue: value.intValue)
            else {
                // Default value when no value has been set for the property before
                return .none
            }
            
            return style
        }
        
        set {
            objc_setAssociatedObject(self, &Key.style, NSNumber(value: newValue.rawValue), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}

As shown below, the computed property can be used directly from both Objective C and Swift code.

// In an Objective C implementation file
MyClass *myClass = [[MyClass alloc] init];
myClass.style = StringStyleBold;
NSLog(@"Style: %ld", myClass.style);

// In a Swift file
let myClass = MyClass()
myClass.style = .bold
print("Style: \(myClass.style)")

I've found this technique especially helpful in a mixed Swift/Objective C code base where new functionality is being added in Swift, but Objective C code that can't be converted yet needs to take advantage of new functionality too. Eventually, when all Objective C code is converted, it's a simple task to replace the computed property with a true property since no code outside of the property needs to be changed.

Swift: Simplifying Dictionary Processing

Update: A few weeks after this post, I came across information about Swift 4 updates that I hadn't seen before. A new feature for Dictionaries in Swift 4 is similar to what I was aiming to provide with the code shown in this post. It works well for definitively typed dictionaries (e.g. [String: String]), but it doesn't help with mixed type dictionaries (like [String: AnyObject]) because it still requires two type casts to get from the AnyObject in the dictionary to the object type that needs to be pulled out. For example, pulling a String out of a dictionary of type [String: AnyObject] would look like this:

event.location = dictionary["location", default: "TBD" as AnyObject] as! String

So, I still prefer the technique in this post to the Swift 4 provided solution.

tl;dr

// I wanted to make statements like this:
event.location = dictionary["city"] as? String ?? "TBD"
event.recurring = dictionary["recurring"] as? String ?? false

// More readable with something like this:
event.location = dictionary["city", defaultTo: "TBD"]
event.recurring = dictionary["recurring", defaultTo: false]

// And ended up with this:
event.location = dictionary[("city", defaultTo: "TBD")]
event.recurring = dictionary[("recurring", defaultTo: false)]

// And this for setting values for which nil is OK:
event.revenue = dictionary[("revenue", isType: Float.self)]

-----

Pulling apart a dictionary of data to populate a model object often involves some coding gymnastics. There are several outcomes to consider. For a given key, maybe the dictionary:

  • Contains a value of the expected type.
  • Contains a value but not of the expected type.
  • Doesn't contain a value.

When there is an error, I still want to set a valid value in the model object. So, I often ended up with code like this to pull a value out of a dictionary:

// Just making up an imaginary model object called 'event' 
// that will get some property values from a dictionary.
event.location = dictionary["city"] as? String ?? "TBD"

This is perfectly fine. But it's kind of ugly. Imagine a list of statements like this to fill out an "event" model object that has two dozen properties to pull out of the dictionary. Ugh. I also enjoy taking advantage of Swift's type inference machinery anywhere I can to reduce type casting in code.

Initially I extended Dictionary to include a function that was more readable if not slightly longer code. It looked like this:

public func value<T: Any>(for key: Key, defaultsTo: T) -> T {
    if let value = self[key] as? T {
        return value
    }        

    return defaultsTo
}

// At the call site, it looked like this:
event.location = dictionary.value(for: "city", defaultsTo: "TBD")

Again, this is perfectly fine. Any programmer can guess what this is doing without knowing Swift operator syntax for casting and nil-coalescing. But I've traded in harder to read code for boiler plate in the function name and arguments (imagine a dozen lines repeating the ".value(for:" and "defaultsTo:" parts of that function). I really wanted to continue accessing dictionary values using a subscript notation to avoid too much extra boiler plate. Alas, this was not possible... until Swift 4.

Swift 4 adds support for generic subscript operators. This is exactly what I needed to achieve the type inference I desired with subscript notation on a Dictionary.

But, a subscript can only take a single argument. This limitation can be skirted by using a tuple as the single argument passed to the subscript function. Here is an implementation:

extension Dictionary {
    /**
    Allows subscripting of a dictionary with a tuple that includes the
    dictionary key and a default value. If there is not a value for the
    provided key or if the value found is not of the same type as the
    provided default value, then the default value is returned.
    */
    subscript<T: Any>(tuple: (key: Dictionary.Key, defaultTo: T)) -> T {
        if let value = self[tuple.key] as? T {
            return value
        }

        return tuple.defaultTo
    }
}

// At the call site, this yields:
event.location = dictionary[("city", defaultTo: "TBD")]

// If you prefer, since the argument is a tuple, 
// you can even omit all of the interior argument labels.
even.location = dictionary[("city", "TBD")]

This gets really close to the fanciful outcome I was aiming for.

While the above works well for values that are never nil, it isn't useful for setting variable values for which nil is acceptable. A dictionary lookup and conditional type cast can be used for those cases. For the sake of completeness and code consistency, a second subscript function that doesn't use a default value but still provides type checking can be defined and used like this:

extension Dictionary {
    /**
    Allows subscripting of a dictionary with a tuple that includes the
    dictionary key and the expected type of the value.
    If there is not a value for the provided key or if the value found is
    not of the expected type, then nil is returned.
    */
    subscript<T: Any>(tuple: (key: Dictionary.Key, ofType: T.Type)) -> T? {
        return self[tuple.key] as? T
    }
}

// At the call site, this yields:
event.location = dictionary[("city", ofType: String.self)]

// Or, without the argument label:
event.location = dictionary[("city", String.self)]

Swift: Simple Generic UITableView Extensions

If you're looking to make your first steps into Swift generics, here are a couple of very simple yet useful examples. I assume basic knowledge of what generics are, but provide a little more explanation of how these particular functions work with types. The code shown is using Swift 3 syntax.

UITableView has some functions that ask for a cell reuse identifier, which is a string. Specifying strings as arguments is always less desirable than specifying a real type that the compiler has knowledge of, so whenever a string argument can be replaced by a real type, it's a great idea to do so. Some of the benefits include:

  • Compile time checking of the real type instead of a potential run time failure on a mistyped string
  • Code completion hints are given when typing the name of a real type
  • If a faulty string is entered there is no immediate warning or error, but Xcode will give an error immediately if an unknown type is entered

The following extensions rely on the following convention: a UITableViewCell subclass' name, xib file name, and reuse identifier are always the same. Given that, we can use a class name to get the reuse identifier (since it is the same name) and the nib (by loading the nib with the same name). If we can also convert a class type to a class name (as a String), then we can replace the use of Strings with class types, gaining the benefits noted above. After showing the extension functions, I'll discuss a little bit more about how they work.

Here's the first extension:

extension UITableView {
/**
Registers a cell with the table view.
Depends on the assumption that the cell's reuse identifier matches its class name.
If a nib is found in the main app bundle with a filename matching the cell's class name, that nib is registered with the table view. Otherwise, the cell's class is registered with the table view.
- parameters:
   - type: The class type of the cell to register.
*/
    func registerCell<T: UITableViewCell>(ofType type: T.Type) {
        let cellName = String(describing: T.self)
        
        if Bundle.main.path(forResource: cellName, ofType: "nib") != nil {
            let nib = UINib(nibName: cellName, bundle: Bundle.main)
            
            register(nib, forCellReuseIdentifier: cellName)
        } else {
            register(T.self, forCellReuseIdentifier: cellName)
        }
    }
}

As shown below, this extension function slightly simplifies table view setup code and provides the type checking benefits noted at the start of this post.

// Instead of this
let nib = UINib(nibName: "CustomTableViewCell", bundle: Bundle.main)
tableView.register(nib, forCellReuseIdentifier: "CustomTableViewCell")

// We can do this
tableView.registerCell(ofType: CustomTableViewCell.self)

Here's the second extension:

extension UITableView {
/**
Dequeues a cell that has been previously registered for use with the table view.
Depends on the assumption that the cell's class name and reuse identifier are the same.
- parameters:
   - type: The class type of the cell to dequeue.
- returns: A UITableViewCell already typed to match the `type` provided to the function.
*/
    func dequeueCell<T: UITableViewCell>(ofType type: T.Type) -> T     {
       let cellName = String(describing: T.self)
        
       return dequeueReusableCell(withIdentifier: cellName) as! T
    }
}

Again, this extension function simplifies code at the call site and provides type checking, as show below:

// Before having the extension, we might have had code like this to dequeue and populate a cell:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    // This is the line that will change
    let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell") as! CustomTableViewCell

    // Populate the cell here
    
    return cell
}

// Now, the one line changes and we have this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueCell(ofType: CustomTableViewCell.self)

    // Populate the cell here
    
    return cell
}

So, what's happening in these extensions? Lets deconstruct the second extension for a better understanding. Here it is again with more explanation:

/*
The function signature is standard for generics with one exception. The argument is of type `T.Type`. Using `.Type` indicates the function is expecting an actual type, not an instance of the type.
*/
func dequeueCell<T: UITableViewCell>(ofType type: T.Type) -> T {
   /*
   String provides this initializer that gets the name of a type as a String. 
   Note that when passing a type into a function, the type must be suffixed with `.self`.
   */
   let cellName = String(describing: T.self)
        
   /*
   This is the call to the standard UITableView function we are wrapping. It is cast to the type provided to this function. Otherwise the object returned is considered to be of type UITableViewCell by the compiler. Doing the cast here simpilfies code at the call site for this function.
   */
   return dequeueReusableCell(withIdentifier: cellName) as! T
}

Here's the call site code with a little more explanation:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    /*
    Again, when passing a type into a function rather than an instance, use the type name with the suffix `.self`. The standard UITableView function returns a UITableViewCell object that must typically be cast to the subclass type before working with the object. But our extension function performs the cast for us, so the cell will be of type CustomTableViewCell already.
    */
    let cell = tableView.dequeueCell(ofType: CustomTableViewCell.self)

    // Populate the cell here
    
    return cell
}