book covers

Indie macOS Dev Bundle, Swift 3 Ed..

Design solid applications and own your distribution process. Learn software architecture principles to make your Swift apps easier to maintain and extend. Set up your app for sale, with a trial mode and license generation all set. Including fully functional sample projects and code templates for your app.

NSTextView: When Did the Find Bar Disappear?

For whatever reason, my current app project’s find bar does not make the text view firstResponder again when you hit Escape or click the “Done” button to close it. This is very uncomfortable for users: they type away, hit ⌘F to find a phrase, then hit Esc – and now they’re in limbo.

To my astonishment, the NSTextFinderAction called hideFindInterface is not triggered when you make the find bar disappear. Its opposite, showFindInterface, is triggered when the find bar slides back in, though. Intercepting in NSTextView.performTextFinderAction(_:) does not help, then.

I embed my text view in a NSScrollView, which conforms to NSTextFinderBarContainer. There, you have a mutable (!) isFindBarVisible property. Since it’s mutable, you can write a Swift property observer in a subclass:

class MyScrollView: NSScrollView {
    override var isFindBarVisible: Bool {
        didSet {
            if oldValue == false && isFindBarVisible == true {
                // find bar is closed
            }
        }
    }
}

You can also use key–value-observation for this property if you want to avoid the subclass.

I am also using RxSwift in this project, so writing a KVO property observer is as “simple” as this:

class AmazingViewController: NSViewController {

    @IBOutlet var textView: NSTextView!
    @IBOutlet var scrollView: NSScrollView!

    fileprivate let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()
        wireFindBarDisappearanceToCursorFocus()
    }

    fileprivate func wireFindBarDisappearanceToCursorFocus() {

        scrollView.rx.observe(Bool.self, "findBarVisible")
            .filterNil()  // from RxOptional
            .skip(1)      // Don't need the initial value
            .map { !$0 }  // So I don't have to write `!didBecomeVisible`
            .distinctUntilChanged()
            .asDriver(onErrorJustReturn: false)
            .drive(onNext: { [weak self] didDisappear in
                guard didDisappear else { return }
                self?.textView.makeFirstResponder()
            })
            .disposed(by: disposeBag)
    }
}

// I was tired of unwrapping all the view?.window?.makeFirstResponder(view) calls:
extension NSView {
    func makeFirstResponder() {
        self.window?.makeFirstResponder(self)
    }
}

This helps. But I don’t trust all this NSTextFinder related stuff, I admit. It’s a bit too finicky for my taste, overall.

Exposing the MultiMarkdown 6 Library to Swift, Part 1: Swifty Enums

During the time between Christmas and New Year, which we tend to call the time “between the years” where I live in Germany, I wanted to do something fun, but not too fun so I don’t get spoiled.

That’s how I turned up experimenting to use libMultiMarkdown from within a Swift app. The amount of fun I have when reading and writing C code is negligible, which made it a perfect fit.

And, frankly, I think using the official MultiMarkdown library is a good approach to perform proper syntax highlighting in an editor. Much better than my home-brewed stuff can ever be. While writing a “minimum viable” Markdown highlighter yourself is pretty easy, the edge cases are aplenty, and the long term maintenance overhead is too big for my taste. So I really don’t want to bother making my own highlighter useful much longer and switch to a better, more performant solution.

Getting the current MultiMarkdown 6 project to generate an Xcode project with a local build directory and output the library header file in the first place was a bit of a chore. More about that some other day.

Exposing the token types as enums

In the wild west of C code, you end up with a header file with free functions. Calling these from Swift is straightforward. More bewildering to use are the enums which you need to do anything with the resulting tokens. They look innocent enough, like this:

enum token_types {
    DOC_START_TOKEN = 0,    //!< DOC_START_TOKEN must be type 0

    BLOCK_BLOCKQUOTE = 50,        //!< This must start *after* the largest number in parser.h
    BLOCK_CODE_FENCED,
    BLOCK_CODE_INDENTED,
    BLOCK_DEFLIST,
    BLOCK_DEFINITION,
    BLOCK_DEF_ABBREVIATION,
    BLOCK_DEF_CITATION,
    BLOCK_DEF_GLOSSARY,
    BLOCK_DEF_FOOTNOTE,
    BLOCK_DEF_LINK,
    BLOCK_EMPTY,
    BLOCK_HEADING,                //!< Placeholder for theme cascading
    BLOCK_H1,                    //!< Leave H1, H2, etc. in order
    BLOCK_H2,
    // ...
}

But the resulting Swift code is very noisy because these C enum cases are exported as root-level constants, and the resulting types don’t even match Swift’s expectations, so you have tons of type casts:

let token: UnsafeMutablePointer<token> = // ...
switch token.pointee.type {
case UInt16(BLOCK_BLOCKQUOTE.rawValue): // ...
case UInt16(BLOCK_DEFLIST.rawValue): // ...
default: break
}

We get useful Swift enums when we use NS_ENUM in Objective-C. Since libMultiMarkdown is not a Swift module but a C library, I think a proper NS_ENUM in Objective-C is a good start. With that in place, you can use it from both Objective-C and Swift.

The expected code would look like this:

typedef NS_ENUM(NSUInteger, MMD6TokenType) {
    MMD6TokenTypeDocStartToken = DOC_START_TOKEN,
    MMD6TokenTypeBlockBlockquote = BLOCK_BLOCKQUOTE,
    MMD6TokenTypeBlockCodeFenced = BLOCK_CODE_FENCED,
    MMD6TokenTypeBlockCodeIndented = BLOCK_CODE_INDENTED,
    MMD6TokenTypeBlockDeflist = BLOCK_DEFLIST,
    MMD6TokenTypeBlockDefinition = BLOCK_DEFINITION,
    MMD6TokenTypeBlockDefAbbreviation = BLOCK_DEF_ABBREVIATION,
    MMD6TokenTypeBlockDefCitation = BLOCK_DEF_CITATION,
    MMD6TokenTypeBlockDefGlossary = BLOCK_DEF_GLOSSARY,
    MMD6TokenTypeBlockDefFootnote = BLOCK_DEF_FOOTNOTE,
    MMD6TokenTypeBlockDefLink = BLOCK_DEF_LINK,
    MMD6TokenTypeBlockEmpty = BLOCK_EMPTY,
    MMD6TokenTypeBlockHeading = BLOCK_HEADING,
    MMD6TokenTypeBlockH1 = BLOCK_H1,
    MMD6TokenTypeBlockH2 = BLOCK_H2,
    MMD6TokenTypeBlockH3 = BLOCK_H3,
    MMD6TokenTypeBlockH4 = BLOCK_H4,
    // ...
} NS_SWIFT_NAME(TokenType);

I wrote a Ruby script to generate the header file code for this.

Note about type names: In C, it makes sense to pluralize the enum’s name, as in token_types, because it reads like a grouping; when you prefix the NS_ENUM cases with the type name, you drop it, because you address the case individually, not like a collection: MMD6TokenTypeBlockHeading, not MMD6TokenTypesBlockHeading. In Swift, you don’t pluralize enum type names, either, using TokenType.blockHeading and passing tokenType: TokenType parameters around, not tokenTypes: TokenTypes, which again read like collections. So the plural S needs to be dropped. The script has brittle hard-coded depluralization built in.

Get the code generator as a Gist.

Run the generator like this to generate the NS_ENUM code:

ruby cocoaconv.rb path/to/libMultiMarkdown.h

You can also generate better readable Swift enum case descriptions:

ruby cocoaconv.rb -m swift path/to/libMultiMarkdown.h

The latter will print out code like the following:

extension TokenType: CustomStringConvertible {
    public var description: String {
        switch self {
            case .docStartToken: return "TokenType.docStartToken"
            case .blockBlockquote: return "TokenType.blockBlockquote"
            case .blockCodeFenced: return "TokenType.blockCodeFenced"
            case .blockCodeIndented: return "TokenType.blockCodeIndented"
            case .blockDeflist: return "TokenType.blockDeflist"
            case .blockDefinition: return "TokenType.blockDefinition"
            case .blockDefAbbreviation: return "TokenType.blockDefAbbreviation"
            case .blockDefCitation: return "TokenType.blockDefCitation"
            case .blockDefGlossary: return "TokenType.blockDefGlossary"
            case .blockDefFootnote: return "TokenType.blockDefFootnote"
            case .blockDefLink: return "TokenType.blockDefLink"
            case .blockEmpty: return "TokenType.blockEmpty"
            case .blockHeading: return "TokenType.blockHeading"
            // etc.
        }
    }
}

Maybe this’ll make its way into the code repository. I’m working on a series of Pull Requests right now to make the library more accessible for Cocoa developers, both Objective-C and Swift.

Using the new enums in a Cocoa project

With the power of my script, these are the steps you need to perform:

  1. Generate the NS_ENUM code,
  2. Store it in a .h file in your project (e.g. MMD6Enums.h),
  3. Add the following to the top of the file:
#import <Foundation/Foundation.h>
#import <libMultiMarkdown/libMultiMarkdown.h>
#import <libMultiMarkdown/token.h>
#import <libMultiMarkdown/d_string.h>

If you’re not coding in Objective-C, you then need to import the MMD6Enums.h in your TARGETNAME-Bridging-Header.h file to expose the results to Swift.

You can then use it like so:

func applyHighlightingForTokenTree(_ token: UnsafeMutablePointer<token>) {
    let tokenType = TokenType(rawValue: UInt(token.pointee.type))!

    switch tokenType {
    case .blockBlockquote: // highlight blockquote block
    case .pairEmph: // highlight emphasized span
    case .emphStart, .emphStop: // highlight the asterisks or underscores differently
    // ...
    }
}

All of this is still too much work for my taste. Nobody wants to do that. When I figure out what else I want to change to make libMultiMarkdown usable in Swift, I’ll create a wrapper library for Swift PM, Carthage, CocoaPods and whatnot. I’m not certain if that should be part of the MMD6 project itself or a separate repository, though, but I think Fletcher, the author of MultiMarkdown, will come up with a plan. Meanwhile, I’ll keep making PRs.

Month 13 Is Out Of Bounds

Month 13 is out of bounds” appeared in my Xcode console logs today. But I don’t do date arithmetics.

When you create an empty macOS Cocoa app from the template, the message shows, too. It’s emitted before applicationWillFinishLaunching(_:) is called.

Looking at the Console.app output of other processes, I saw this was all over the place. TextMate, loginwindow, User Event Agent – every app is triggering this message.

Rdar or GTFO, right? – rdar://35792221

Let’s hope this does not indicate any important framework part is broken.

This is both humbling and worrying. Humbling, because Apple engineers make just the same silly mistakes as us app developers. Worrying, because having a working macOS is rather important to a lot of people around the globe, and while this message does not prevent me from using my Mac or any apps so far, bugs like these could have people killed in other contexts (think aerospace or autonomous cars).

Getting Worse

Update 2017-11-06: (Yes, I’m back on Nov. 6th! :) Seriously, it’s now Monday, Dec 4th.) Like some other people I was suddenly suffering from 100% CPU usage by the process UserEventAgent which also consumed RAM at a rate of about 4GB/ every 3 minutes. Disk swapping galore, my Mac turned unusable quickly. Only way I found to get rid of this:

  1. Deactivate automatic date and time setting
  2. Reset the date back to something in November
  3. Force quit the UserEventAgent process

Note that this only happened after rebooting. So if you can, do not shut down your Mac for a while just to make sure.

Why the Selection Changes When You Do Syntax Highlighting in a NSTextView and What You Can Do About It

On iOS, this does maybe not happen at all, but when you want to write syntax highlighting code for macOS apps, copying together stuff from around the web, you’ll end up with broken application behavior. In short: when you type and the attributes of the line change, the insertion point is moved to the end of the line. That sucks.

TL;DR: Do not perform style changes inside of NSTextStorage.processEditing() or NSTextStorageDelegate methods but subscribe to NSText.didChangeNotification or NSTextDelegate or NSTextViewDelegate.textDidChange(_:).

Description of the Problem

Illustrated in steps, it looks like this when you edit a line at the beginning and change the color of the whole line in accordance to the syntax:

The user types #, followed by a space character, to change the text line to a heading in Markdown and ends up with the caret at the end of the line

A lot of examples on the web are based off of NSTextStorage subclasses. Others use the NSTextStorageDelegate.textStorage(_:willProcessEditing:range:changeInLength:) callback with similar results. To simplify the explanation, let’s assume you subclass NSTextStorage and override processEditing() to apply syntax highlighting as advertised on objc.io:

class CustomTextStorage: NSTextStorage {
    // ... rest of the text storage methods ...

    override func processEditing() {
        processSyntaxHighlighting()

        // Apply highlighting before super so that attribute changes are combined
        super.processEditing()
    }

    func processSyntaxHighlighting() {
        // Parse text based on `self.editedRange` and apply styles, e.g.:
        let paragraphRange = self.string.paragraphRange(for: self.editedRange)
        if paragraphRange.hasPrefix("# ") {
            self.addAttributes([.foregroundColor : NSColor.red], 
                range: paragraphRange)
        }
    }
}

This wireframe applies highlighting to any edited line starting with # and then moves the selection to the end of the line. That means the position of the text caret – or “insertion point”, as the text view calls it – is not where the last user change happened anymore.

This is a widespread problem and the question is often asked on the web; people offer different work-arounds and quick fixes but no-one addressed the source of the problem so far, thus resulting in only 90% correct behavior.

Fixing the Editing Process to not Move the Selection (Warning: All Dead End)

To make sure you see which approaches will not be fruitful (and why), let’s go through a couple of work-arounds.

You can skip these approaches if you want to see the non-failing attempt.

Overriding Private NSLayoutManager API

In a talk from 2012, Max Seelemann of The Soulmen (the creators of Ulysses) showed the audience how to react to this odd phenomenon by applying a post-edit fix, overriding private API in NSLayoutManage._fixSelectionAfterChange(inCharacterRange:changeInLength:). (A video recording of the talk is only available in German.) That does indeed help with the insertion point, but if experiment further, you’ll bump into new display glitches and scrolling issues.

Keep in mind that 2012 was before Ulysses 3 shipped, and it’s 5 macOS versions ago. Maybe this was the only way to fix this behavior of the Cocoa text system back then. Compiling against the latest 10.13 SDK and deploying an application for macOS 10.11 and above, I can safely say that modern apps have no need to resort to this.

This points into the right direction, though: the NSLayoutManager is responsible for changing the position of the caret by altering the selection during processEditing().

Not triggering the NSLayoutManager

You can avoid moving the selection if you do not notify the text system of changes to attributes. That means you do not call NSTextStorage.edited(_:range:changeInLength:) with .editedAttributes in your CustomTextStorage.addAttributes(_:range:) implementation:

class CustomTextStorage: NSTextStorage {

    /// Switch used to prevent style changes in `processEditing` from
    /// triggering callbacks.
    fileprivate var isBusyProcessing = false

    override func processEditing() {
        self.isBusyProcessing = true
        defer { self.isBusyProcessing = false }

        processSyntaxHighlighting() // same as above

        super.processEditing()
    }

    /// The real implementation to delegate changes to.
    let content = NSTextStorage()

    override func setAttributes(_ attrs: [NSAttributedStringKey : Any]?, range: NSRange) {

       // When we are processing, `edited` callbacks will
       // result in the caret jumping to the end of the document, so
       // do not send them!
       guard !isBusyProcessing else {
           content.setAttributes(attrs, range: range)
           return
       }

       beginEditing()
       content.setAttributes(attrs, range: range)
       self.edited(.editedAttributes, range: range, changeInLength: 0)
       endEditing()
   }

   // ... rest of NSTextStorage implementation ...
}

This implementation will apply color changes but not move the insertion point.

It’s a 70% winning solution.

The remaining 30% are non-functional block changes. When you change the style of a block of text that exceeds the line of the insertion point (like a block comment, or something else that spans multiple laid-out lines in the text view), only the current line will be updated. The other lines will have new style information, but the layout manager will not schedule actually drawing them – until you select them with the mouse or move the caret inside with the arrow keys, say.

Invalidate the glyphs in NSLayoutManager to support block changes

So multi-line blocks of text do not redraw with the last approach. When I was so close to success a few weeks ago, I struggled to find anything to force-redraw the rest of the text as needed.

I tried two things:

  1. Notify NSLayoutManager about the edited attribute range after processEditing() had finished; and
  2. Invalidate a laid-out block of text on screen.

Sending the edited message as usual would, among other things I do not know about, call NSLayoutManager.processEditing(for:edited:range:changeInLength:invalidatedRange:). This is where I tried to hook in, first:

    func processEditing() {
        // Obtain the highlighted text ranges for post-processing:
        let rangesNeedingLayoutFixes: [NSRange] =
            processSyntaxHighlighting()

        super.processEditing()

        // Do the post-processing!!11
        for range in rangesNeedingLayoutFixes {
            for manager in self.layoutManagers {
                manager.processEditing(
                    for: self, 
                    edited: .editedAttributes, 
                    range: range, 
                    changeInLength: 0, 
                    invalidatedRange: range)
            }
        }
    }

This does indeed show attribute changes on screen, which means the layout manager generates new glyphs for the whole block as expected.

But when you hit spacebar or delete backwards, in lots of circumstances the scroll view jiggles or bounces up and down.

Another thing I applied to some limited success was to mark a larger range as invalid before changing the attributes:

func processEditing() {
    // Call super first this time
    super.processEditing()

    // Determine the to-be-highlighted ranges before
    let invalidatedRange: NSRange = ...
    self.layoutManagers.forEach { (layoutManager) in
        layoutManager.invalidateDisplay(forCharacterRange: invalidatedRange)
    }

    processSyntaxHighlighting()
}

That works way better but crashes in some cases, i.e. when the user scrolls the text view and you replace the contents during the scroll operation. Yeah, what a weird one. Imagine how long it took to figure out the source of seemingly unrelated, occasional crashes …

Interfere with Attribute Fixing

A suggestion I found on StackOverflow suggested to override NSTextStorage.fixAttributes(in:) and perform highlighting there.

override func fixAttributes(in range: NSRange) {
    processSyntaxHighlighting()
    super.fixAttributes(in: range)
}

This works because attribute fixing seems to be part of the call chain before the NSLayoutManager is notified. If you highlight inside processEditing, the attribute fixing will encompass the highlighted range; if you override fixAttributes, though, you get the user edited range and make sure to only pass that on to super.

Attribute fixing is important to remove inconsistencies in attribute assignments. Overriding the method means that the NSTextStorage now does not fix attributes for the whole range you applied highlighting to, possibly resulting in an invalid representation of attributes. That does not sound good; breaking attribute fixing by itself is bad in principle but might still not hurt much in practice. See “Using Text Kit to Draw and Manage Text” from the docs for more on attribute fixing.

Please note I haven’t tested how bad this approach really is in practice. I found this and dismissed it for good reasons, no need to benchmark anything: Since attributes are not fixed properly, the layout manager will not be notified about the real range of invalid glyphs resulting from the highlighting. The layout manager probably redraw the current line only, and thus have the same issues with long blocks of text like the last failing approach.

Understanding the Source of the Problem

Highlighting inside processEditing() will move the caret of the text view. Looking at stack traces (“Why and when does the text view scroll after editing? By how much?”) and comparing parameters passed around in private methods of NSLayoutManager and NSTextView, I came up with the following explanation:

NSLayoutManager receives a combined “edited” messages during NSTextStorage.processEditing() that covers all affected ranges.

It goes like this:

  • The user types in the text view. Her change affects only the typed-in character range, resulting in an editMask of [.editedCharacters, .editedAttributes] for the limited range of the edit. In the heading example from above, it would be for an affected character range of NSRange(1..<2) for typing the space character after the hash with a changeInLength of 1. This is just the expected notification.
  • The syntax highlighting during processEditing() now interferes. It affects a much broader range, for example the whole paragraph, sending .editedAttributes with a range of, say NSRange(0..<17) in the case of the example line.
  • The text storage combines alls calls to self.edited(...), forming a union of the ranges and a union of the editedMasks. The NSLayoutManager receives only a single callback, via .processEditing(for:edited:range:changeInLength:invalidatedRange:) for the larger range of NSRange(0..<17) with [.editedCharacters, .editedAttributes]. Again: the syntax attribute changes are not received separately.
  • The layout manager triggers a selection change whenever .editedCharacters is received, calling _fixSelectionAfterChange(inCharacterRange:changeInLength:) which Max had introduced above. The edited character range is meant to be much smaller than the changed attribute range, but we got a combined version only, so that’s why _fixSelectionAfterChange receives the larger range.
  • It also triggers NSLayoutManager._resizeTextView(for:) with the whole range instead of the original, much more limited user-edited range. That triggers the bouncing scroll behavior. It’s like selecting and then paste-overwriting the whole block every time you hit a key inside.

Following the process description, you have to avoid expanding the range for the .editedCharacters event when you apply syntax highlighting.

Applying a Real Solution

Once you separate the user-originating text change from the syntax highlighting and end up with 2 layout passes, _fixSelectionAfterChange is only called for the user edit (because it contains .editedCharacters), but not for the attribute change during highlighting. Similarly, _resizeTextView will not be triggered because of style changes.

To end up with two separate layout passes, you have to apply syntax highlighting outside processEditing(). This includes NSTextStorageDelegate callbacks.

The first layout pass is finished when you receive a NSText.didChangeNotification. You can subscribe to it only, or use textDidChange(_:) which is part of NSTextDelegate (and its descendant, NSTextViewDelegate).

Heads up: when you apply attribute changes from outside, make sure to wrap all the highlighting changes in a beginEditing()/endEditing() block or the glyph generation will be triggered immediately for every change, wasting performance.

Here is an approach I find suitable. I don’t use NSTextViewDelegate but the notification mechanism instead because then you can make someone else the delegate if you need one at all. Also, this way the SyntaxHighlighter service is self-contained; if it was the delegate, you could unintentionally disable syntax highlighting by changing the text view’s delegate to another object. Which would leave you with a monster delegate that does everything. Nobody likes that, so here you are:

class ViewController: NSViewController {

    var textView: NSTextView!
    var syntaxHighlighter: SyntaxHighlighter!

    override func viewDidLoad() {
        super.viewDidLoad()
        // ...
        self.textView = // ... or use IBOutlet
        self.syntaxHighlighter = SyntaxHighlighter(textView: self.textView)
    }
}

class SyntaxHighlighter {
    let textView: NSTextView

    private var subscription: NSObjectProtocol

    /// - param textView: The text view which should be observed and highlighted.
    /// - param notificationCenter: The notification center to subscribe in.
    ///   A testing seam. Defaults to `NotificationCenter.default`.
    init(textView: NSTextView, 
        notificationCenter: NotificationCenter = .default) 
    {
        self.textView = textView
        self.subscription = notificationCenter.addObserver(
            forName: NSText.didChangeNotification, 
            object: textView, 
            queue: nil) { [unowned self] notification in
                self.textViewDidChange(notification)
        }
    }

    func textViewDidChange(_ notification: Notification) {

        // This implicit type expectation is not Good Code.
        // Prefer to use a NSTextView subclass that codifies this 
        // dependency (and offers a `processSyntaxHighlighting` method itself).
        guard let customTextStorage = self.textView.textStorage as? CustomTextStorage 
            else { return }

        customTextStorage.beginEditing()
        customTextStorage.processSyntaxHighlighting()
        customTextStorage.endEditing()
    }
}

The notification is, as usual, sent synchronously. So your highlighting code will be executed right after the user hits a key (and after the change itself has been processed) without delay in the same run loop iteration. That means you won’t have a visible delay.

You can take chances and write asynchronous highlighting code, but that quickly looks weird. In complex situations, edited characters will now not appear after a delay; they will appear immediately. But the style changes are delayed, which in some ways feels even weirder.

I found it favorable to tolerate delays in synchronous highlighting that is noticeable (probably above the 100ms response threshold) which indicates: something is working hard here. Having immediate textual feedback but delayed style changes felt like the highlighter was too lazy to do its job properly. Especially so when you abort pending highlighting requests when the user types too quickly.

So that’s it, the most comprehensive explanation of the problem of syntax highlighting in NSTextViews affecting the caret location – and the only working solution that’s not just a half-assed work-around that looks good in demos but fails tests for production-level quality.

Feel free to share other half-baked solutions that kind of worked but eventually let you down in the comments and I’ll expand the list!

Blogs Merged Back Into One

I have migrated blog posts I published at cleancocoa.com over the past months back to this place. It was nice hosting the project on GitHub Pages, but in the end I never really wanted to post articles elsewhere.

The original problem of my web imperium still persists: on this personal page, both my coding stuff and my software need a hub. A proper next step is to create a better website index to direct casual visitors, I guess, and improve the website navigation.

It was fairly easy to separate the Zettelkasten Method project a couple of years ago because the two topics didn’t work well in one blog. But since then, the blog part was exclusively about programming. Tearing that out, too, just didn’t feel right after a while. Gut reactions aside, with the years I’m growing more worried when I do experiments like that because these personal decisions are also business decisions. I’m slowly becoming more professional in my concerns, I guess!

Dependency Injection via the Recent “Cake Pattern in Swift” Pattern is Useless in Practice

Dependency Injection means you do not create objects where you use them but “inject” objects a function/method/object depends on from outside. This is a useful trick to make code testable, for example. Once you adopt the mindset, it becomes second nature.

From the Java world stems the imperative to program against interfaces, not implementations. In Swift, this means to define injected dependencies not as concrete types but as protocols.

In an ongoing object collaboration, you will want to store the dependency as a property. The storage of the dependency is up to the component itself. Now the, let’s say, “injectability” can be lifted into a protocol, too. Then you can provide a protocol extension with a default implementation. That’s what Peter-John did in “Dependency Injection with the Cake Pattern” value.

The problem with this approach is that it has 0 real world value and is totally misleading because with that code you will not be able to actually inject anything; you’ll be hiding object creation in a protocol extension only.

Dependency injection is a useful pattern because it allows you to change the concrete object passed in. As I mentioned, apart from the final object in your production code, tests will benefit from injections a lot. When you do not write tests and never pass in another object in production code, you do not need dependency injection. “But it makes my code cleaner!”, people arguing based on principles will say. Yeah sure, it reads like cleaner code, but it’s useless code written like useful code in a “clean” manner. Getting rid of that code is more important than sticking the dependency injection label on it.

Look at the sample code from Peter-John. Here is the dependency as a protocol and some default implementation:

protocol ProductsRepository {
    func fetchProducts() -> [Product]
}

struct ProductsRepositoryImplementation: ProductsRepository {
    func fetchProducts() -> [Product] { return [] }
}

And here is the “having a dependency”-protocol, which is the result of what I called “lifting injectability into a protocol”:

protocol ProductsRepositoryInjectable {
    var products : ProductsRepository {get}
}

extension ProductsRepositoryInjectable {
    var products : ProductsRepository {
        return ProductsRepositoryImplementation()
    }
}

This protocol with its extension will help you get rid of writing client code like this:

class ClientLong {
    let products: ProductsRepository

    // Inject dependency in initializer:
    init(products: ProductsRepository) {
        self.products = products
    }

    func printPrices() {
        self.products.fetchProducts().forEach {
            print("This \($0.name) costs R\($0.price)")
        }
    }
}

Instead you can start with a shorter implementation of ProductsRepositoryInjectable:

class ClientShort: ProductsRepositoryInjectable {
    func printPrices() {
        self.products.fetchProducts().forEach {
            print("This \($0.name) costs R\($0.price)")
        }
    }
}

ClientShort().printPrices()

/*
 This Adidas Sneakers costs R2030.0
 This Nike Sneakers costs R1000.0
 */

There you have it: less code, using cleverly conceived protocols.

There are two very obvious problems:

  • Computed properties don’t work well for non-trivial object creation, for example if setting up the dependency in turn depends on some other dependency; you will want to store the objects. So a *Injectable protocol with a default extension might not always work.
  • No injection, but lots of hand-waving: it doesn’t help a bit when you actually want to reap any benefits of dependency injection, like, injecting a dependency. The code as cited does not allow injection of dependencies. It only hides object creation. To change the dependency in tests, you will need to define a property and override it somehow, via initializer injection or by making the property mutable internally. In any case, you will end up with code similar to ClientLong.

That’s when I concluded that this approach is not going to help you improve your code at all. There has to be more to make it useful in practice. All it does now is shorten the code of a contrived example to impress the reader.

A comment on the original post asked how to use this to inject mocks in tests, and Peter-Johns answer was along the lines of: use a dependency container singleton to create a testing seam. The protocol extension would then return DependencyContainer.instance.productRepository instead of creating a new instance. Actually providing a testing seam is an improvement. It has nothing to do with the pattern, though.

What you will want is code similar to ClientLong to keep the mechanism of injecting dependencies local. Then you use the initializer directly to inject your mock repository: ClientLong(products: mockRepository). You can do this a million times and it will Just Work. But forget to reset a dependency container singleton once and a lot of other tests that use the container will suffer and may even break. It’s also a lot less straightforward to read and understand than the initializer, thus increasing maintenance cost. If you think that accidentally breaking unit tests is a sign of bad tests, you’re right, and writing atomic unit tests for very cohesive objects is an obvious antidote – and now we’ve done a full circle, looking at unit tests for ClientShort which suffer from the very same problem.

A verdict from the author himself in the comment section on Medium is: this is only part 1 to show the basic technique. But, as I argued, it does not show actual dependency injection. It hides object creation in a protocol extension only.

If you take away anything from my post here, it should be that nice-looking samples do not always convey meaningful information, and that slapping “Pattern” onto something does not make it awesome. Or even useful.

Is the Mac mini (Mid 2011) a good developer device in 2017?

Short answer: No.


My trusty Mac mini served me well for years thanks to its 8 GB RAM and the 256 GB SSD. An SSD really helped make it faster back in the day. But with Xcode 9 and macOS 10.13 “High Sierra”, the machine begins to stutter.

I think it’s the CPU not really liking what I demand from it. Xcode 9 builds take a ton longer and the UI is less responsive. Sure, Xcode 9 sports a UI overhaul and might not be as performant as it could be, yet. That doesn’t help with the compile times which, for my current project, now take up to 5mins; that’s not even a fresh build.

So if you want to develop apps with Swift 4 and on the latest macOS, better get a more recent device. I don’t know which to recommend; the MacBook Pro is traditionally a good fit, but an iMac (or upcoming iMac Pro with its uncountable amount of CPUs and endless RAM) might be a good fit, too. Listen to Under the Radar ep. 89 for a more in-depth discussion by Marco Arment and David Smith.

I’d prefer a faster Mac mini because I have a nice-looking screen already and work at my desk 99.99% of the time anyway.

Inject ReSwift Middlewares from Different Project Targets During Runtime

Say you extract the ReSwift-based state module with all your app’s state types, reducers, and middleware into its own framework target. Until you add middlewares to the mix, it’s easy to keep this coherent.

Injecting side-effects through middleware is not easy to do, though, as long as you provide the Store instance from your state module. The store takes an array of Middleware upon initialization. They cannot be changed later. The state module would then depend on your app module with all its network request services and whatnot. That’s the wrong way around, also resulting in a circular dependency. Instead, you have two options to add side-effects that are inherently part of your app’s module, not of the state module:

  1. Create the store inside the app module, not in the state module;
  2. Add a general-purpose side-effect middleware that exposes mutation functions to the outside world.

The latter can look like this:

SideEffectRegistry.instance
    .addBeforeReducers { (bananaAction: BananaAction) in 
        Swift.print("Banana action passing through: \(bananaAction)") }

As a bonus (and risk!), this approach allows you to change which middleware are active during runtime. Keep in mind that ReSwift is designed not to allow this, so proceed with caution.

The closure is of type SideEffect. I found it beneficial to not have SideEffect take just any ReSwift.Action by default, because I usually conditionally check for one specific type, not multiple. So I lift the action type filtering to a generic constraint:

public typealias SideEffect<A : Action> = (_ action: A, _ dispatch: DispatchFunction) -> Void

Now you cannot create an array from these function bodies anymore; also, though the Action subtype is now reified as a generic constraint, the actual cast from Action to A has to go somewhere. I put it into a AnySideEffect box:

struct AnySideEffect {
    let boxedSideEffect: (Action, DispatchFunction) -> Void

    init<A: Action>(_ base: @escaping SideEffect<A>) {
        self.boxedSideEffect = { action, dispatch in
            guard let castAction = action as? A else { return }
            base(castAction, dispatch)
        }
    }
}

Now you can have an [AnySideEffect] array and pass any Action through. Only matching actions will be passed to interested middleware.

Heads up: This closure-based approach can allow removing all registered SideEffect, but not specific instances. For that, instead of a typealias‘d closure I’d use a reference type and check for reference equality (===) to remove/deactivate them.

Update 2017-09-29: I renamed the types a bit, from ApplicationMiddleware to SideEffect, etc.

The Full Implementation

/// - parameter action: The expected action to perform a side effect on.
/// - parameter dispatch: Default dispatch function into the current store.
public typealias SideEffect<A : Action> = (_ action: A, _ dispatch: DispatchFunction) -> Void

struct AnySideEffect {
    let boxedSideEffect: (Action, DispatchFunction) -> Void

    init<A: Action>(_ base: @escaping SideEffect<A>) {
        self.boxedSideEffect = { action, dispatch in
            guard let castAction = action as? A else { return }
            base(castAction, dispatch)
        }
    }

    func process(action: Action, dispatch: DispatchFunction) {
        boxedSideEffect(action, dispatch)
    }
}

public class SideEffectRegistry {
    public static var instance = SideEffectRegistry()
    private init() { }

    internal fileprivate(set) var sideEffects: [AnySideEffect] = []

    public func addBeforeReducers<A: Action>(sideEffect: @escaping SideEffect<A>) {
        sideEffects.append(AnySideEffect(sideEffect))
    }

    internal func process(action: Action, dispatch: DispatchFunction) {
        sideEffects.forEach { $0.process(action: action, dispatch: dispatch) }
    }
}

let sideEffectsMiddleware: Middleware<AppState> = { dispatch, getState in
    return { next in
        return { action in
            SideEffectRegistry.instance
                .process(action: action, dispatch: dispatch)

            next(action)
        }
    }
}

→ Blog Archive