Attributed Strings

I had to take a string like “Name (whatever)” and display it in a label. The Name part should be bold, and anything in parentheses should use the regular font.

Pretty simple, I just put the string in a NSAttributedString, find the opening parenthesis and add a bold font attribute to everything up to it. If I find no parenthesis I just bold the whole string:

let attributed = NSMutableAttributedString(string: string)
let boldRange = NSRange(string.startIndex ..< (string.range(of: " (")?.lowerBound ?? string.endIndex), in: string)
attributed.addAttributes([.font: UIFont.systemFont(ofSize: 12, weight: .bold)], range: boldRange)

But where should I put this code? The part that specifies the font and other presentation specific things should belong to the view layer. Especially since it has to import UIKit to get UIFont. But parsing the string should go in the model layer. In other views I might want to display that string in a different way, so it makes sense to parse it once.

In this case I could split the string and store both parts separately. Another option is to store the range of the name in addition to the whole string. Both approaches are not very scalable. Once I have multiple ranges to highlight this gets too complicated. What I need is a data structure that can assign values to ranges in a string. There are tons of options how to implement this. But luckily I don’t have to since Foundation provides such a thing: NSAttributedString.

First I define a key for a custom attribute and a type for that attribute:

extension NSAttributedString.Key {
    static let semantic = NSAttributedString.Key(rawValue: "de.5sw.semantic")
}

enum Semantic: Hashable {
    case name
}

Then I parse the string and add the custom semantic attribute:

let attributed = NSMutableAttributedString(string: string)
let nameRange = NSRange(string.startIndex ..< (string.range(of: " (")?.lowerBound ?? string.endIndex), in: string)
attributed.addAttributes([.semantic: Semantic.name], range: nameRange)

The code is basically the same as before, but instead of adding the font attribute I add a custom attribute that specifies the meaning of this part of text.

In the view layer I then enumerate all the ranges with the semantic attribute and add the expected formatting:

let displayString = NSMutableAttributedString(attributedString: model.parsedString)
displayString.beginEditing()
displayString.enumerateAttribute(.semantic, in: NSRange(location: 0, length: displayString.length), options: .longestEffectiveRangeNotRequired) { value, range, _ in
    if let semantic = value as? Semantic, semantic == Semantic.name {
        displayString.setAttributes([.font: UIFont.systemFont(ofSize: 12, weight: .bold)], range: range)
    } else {
        displayString.removeAttribute(.semantic, range: range)
    }
}
displayString.endEditing()

I like this code, now I have a clear separation between the meaning of my data and the way it should be presented.

And since I don’t want to repeat this everywhere I need to style an attributed string I encapsulated this in a handy little extension that uses a dictionary to map my custom attribute to actual styles:

extension NSAttributedString {
    convenience init<T>(attributedString: NSAttributedString, key: NSAttributedString.Key, attributes: [T: [NSAttributedString.Key: Any]], default: [NSAttributedString.Key: Any]? = nil) {

        let copy = NSMutableAttributedString(attributedString: attributedString)
        copy.beginEditing()
        copy.enumerateAttribute(key, in: NSRange(location: 0, length: copy.length), options: .longestEffectiveRangeNotRequired) { attribute, range, _ in
            if let value = attribute as? T, let newAttributes = attributes[value] ?? `default` {
                copy.setAttributes(newAttributes, range: range)
            } else {
                copy.removeAttribute(key, range: range)
            }
        }
        copy.endEditing()

        self.init(attributedString: copy)
    }
}

Factories and Protocol Composition DI

Especially on iOS it’s often necessary to create new objects like new view controllers or such things. This often cannot be avoided. This usually is solved by having the object that creates new objects also require all the dependencies of the objects it wants to create. This of course is not a great thing as changes in one class can ripple through the whole project. The protocol composition approach solves this by having the flow controllers take the whole AppDependency object so they can pass it on.

This solves the problem of having to change some classes when the dependencies of others changes. But it still is bad for testing as you can’t be sure which dependencies are actually needed, and you have no way to influence which class is instantiated. A common solution to this is injecting factory objects that hold all the necessary resources. This of course can result in rather verbose code if a whole new type is created. Luckily closures can also take the role of those factories.

While implementing this I realized that an extra object is not even necessary with the protocol composition DI. The AppDependency object itself can take the role of the factory:

protocol MakesSomething {
 func makeSomething() -> Something
}

extension AppDependency: MakesSomething {
 func makeSomething() -> Something {
 return Something(dependencies: self)
 }
}

That code is not so bad and we can avoid having dependencies on unneeded objects which is good for testing. Usage is like any other dependency:

class MyClass {
 typealias Dependencies = MakesSomething & HasOtherThing
 let dependencies: Dependencies
 
 init(dependencies: Dependencies) {
 self.dependencies = dependencies
 }
 
 func doWork() {
 let something = dependencies.makeSomething()
 something.doWhateverItIsSomethingDoes()
 }
}

Protocol Composition and Dependency Injection

I recently read the article “Using protocol compositon for dependency injection” by Krzysztof Zabłocki. I found this to be a rather interesting technique for doing DI, but when trying to implement it I found it somewhat limited:

  • It doesn’t really handle dependencies that have dependencies themselves.
  • No support for lazy instantiation, everything needs to be instantiated up front.

Lets look at simple and pretty common example of the object graph I wanted to create:

  • A view controller at the leaf level, which needs
  • An object that provides business logic (like the Interactor from the VIPER pattern), which needs
  • the data store (a NSPersistentContainer in my case).

This can be translated pretty easily to this pattern:

protocol HasCoreData {
  var coreData: NSPersistentContainer { get }
}

protocol HasListInteractor {
  var listInteractor: ListInteractor { get }
}

struct AppDependencies: HasCoreData, HasListInteractor {
  let coreData: NSPersistentContainer
  let listInteractor: ListInteractor
}

final class ListViewController: UIViewController {
  typealias Dependencies = HasListInteractor
  let dependencies: Dependencies

  init(dependencies: Dependencies) {
    self.dependencies = dependencies)
    // ...
  }
}

final class ListInteractor {
  typealias Dependencies = HasCoreData
  let dependencies: Dependencies

  init(dependencies: Dependencies) {
    self.dependencies = dependencies)
    // ...
  }
}

This all works fine until I try to fill in my AppDependencies struct – to create it I need an instance of my ListInteractor, and to create that I need the AppDependencies struct. So this is not going to work.

Instead I could create a second struct that only implements HasCoreData and use that to initialise the ListInteractor. This approach will work, but will quickly become messy and as hard to refactor as passing every dependency separately. It also won’t address the point of avoiding eager initialisation.

But there is a simple solution that addresses both problems:

final class AppDependencies: HasCoreData, HasListInteractor {
  lazy var coreData: NSPersistentContainer = NSPersistentContainer(name: "Whatever")
  lazy var listInteractor: ListInteractor = ListInteractor(dependencies: self)
}

By making the AppDependencies a class instead of a struct we can use lazy properties to fulfil the protocol requirements. That way we can’t get into the catch-22 situation I described and we get lazy instantiation for free.

Of course there are some other drawbacks to consider:

  • Cyclic dependencies will cause infinite recursion
  • Objects are created lazily, so if you need eager instantiation of some class you need to manually call the getter