Latest Posts

One Way to Solve Inexplicable Race Conditions in Tests

Today I wrote my first asynchronous test in my latest project and suddenly, during the waitForExpectations run loop, a totally unrelated test’s stuff crashed. To make things worse, it was part of an RxSwift subscription. No idea who kept that alive and where the EXC_BAD_ACCESS really originated.

It helped to make sure that no object references are kept around longer than necessary. In unit tests, this can mean to make your test doubles and collaborating objects optionals:

class BananaTests: XCTestCase {

    var banana: Banana!
    var tree: Tree!
    var monkey: Monkey!
    
    override func setUp() {
        super.setUp()
        tree = Tree()
        monkey = Monkey()
        banana = Banana(on: tree, eatenBy: monkey)
    }
    
    override func tearDown() {
        tree = nil
        monkey = nil
        banana = nil
        super.tearDown()
    }
}

If you just go the lazy route and make the objects properties of the BananaTests class, the objects will be kept around until all tests have finished and the BananaTests instance is being disposed of. With the setup–tear down dance here, we manage to get rid of references right after each test execution.

In case you wonder what the lazy version looks like where the latest references are kept alive:

class BananaTests: XCTestCase {

    var banana: Banana!
    let tree = Tree()      // <- uh oh
    let monkey = Monkey()  // <- guess who stays around ...
    
    override func setUp() {
        super.setUp()
        banana = Banana(on: tree, eatenBy: monkey)
    }
}

I’d love to tell you now that this solved my problem. (It didn’t.) Instead, I want you to keep this in mind as a potential source of problems. Tests for NotificationCenter subscribers will are a great example of problematic tests: the subscribers will continue to receive notifications when other test suites run.

SwiftyBeaver: Record to Array

I am using SwiftyBeaver in TableFlip and my latest project. Doing some robust console and file logging is important, and this library seems to work just fine for my needs.

Except for error reporting. I do not want to attach the whole debug log when folks may report a simple problem. So I figured: maybe it’ll help to have the last 5 or 10 log messages attached upon a first error encounter.

So I wrote a SwiftyBeaver “in memory” destination that is set up next to a file and a console destination:

class InMemoryDestination: BaseDestination {

    var maxHistory = 5
    fileprivate(set) var messages: [String] = []

    override func send(_ level: SwiftyBeaver.Level, msg: String, thread: String, file: String, function: String, line: Int) -> String? {

        let formattedString = super.send(level, msg: msg, thread: thread, file: file, function: function, line: line) ?? "\(msg) (formatting error!)"

        messages = Array(messages
            .appending(formattedString)
            .suffix(maxHistory))

        return formattedString
    }
}

As a means to access these messages, I use a free function-like global closure:

let error = ...
let logMessages = lastLogMessages().joined(separator: "\n")
reportError(error: error, additionalInfo: logMessages)

Here, lastLogMessages is a closure so it can be swapped during runtime:

fileprivate(set) var lastLogMessages: () -> [String] = { return [] }

This then comes in handy when I set up my SwiftyBeaver logger:

let console = ...
let file = ...
let inMemory: InMemoryDestination = {
    let inMemory = InMemoryDestination()
    inMemory.maxHistory = 10
    inMemory.format = "$DHH:mm:ss: $M"
    inMemory.asynchronously = false

    // Here create a closure that points inside the InMemoryDestination:
    lastLogMessages = { return inMemory.messages }

    return inMemory
}()

SwiftyBeaver.addDestination(console)
SwiftyBeaver.addDestination(file)
SwiftyBeaver.addDestination(inMemory)

And that’s it! I get a buffer of 10 log messages and read access to said buffer when I prepare error report emails.

One step closer to releasing a version into the wild.

Swift Protocols with Default Implementations as UI Mixins

Oliver Drobnik of Cocoanetics posted a little gist about a protocol that offers pull-to-refresh for your UITableViews: https://gist.github.com/odrobnik/ae16f4f071ead51d915712818a2279d8

@objc protocol Refreshable
{
    /// The refresh control
    var refreshControl: UIRefreshControl? { get set }
    
    /// The table view
    var tableView: UITableView! { get set }
    
    /// the function to call when the user pulls down to refresh
    @objc func handleRefresh(_ sender: Any);
}


extension Refreshable where Self: UIViewController
{
    /// Install the refresh control on the table view
    func installRefreshControl()
    {
        let refreshControl = UIRefreshControl()
        refreshControl.tintColor = .primaryColor
        refreshControl.addTarget(self, action: #selector(handleRefresh(_:)), for: .valueChanged)
        self.refreshControl = refreshControl
        
        if #available(iOS 10.0, *)
        {
            tableView.refreshControl = refreshControl
        }
        else
        {
            tableView.backgroundView = refreshControl
        }
    }
}

I use protocols for interface abstractions in my model and service layer a lot; but in the UI, I often resort to delegation to classes. I almost never use protocols in the UI that come with default implementations. Now that I think about it, I believe most custom protocols that I do implement in the UI layer are of DisplaysBananas kind – implementations for the view protocol of a presenter.

Oliver’s gist made me think about other techniques to separate concerns in the UI. Not just delegation to sub-view controllers and encapsulation of view data in structs, but maybe a few more protocol abstractions here and there. When they make sense, that is.

Clean Cocoa Blog Redesign

I started and kind-of-finished this step after TableFlip’s release back in November 2016. But then I never pulled the trigger. So the redesign and usage of the cleancocoa.com URL didn’t really happen. Until today.

The website is now hosted on GitHub Pages. And I’m working on building a knowledge base as wiki. Since the website is hosted on GitHub, everyone can propose changes.

I want to provide higher-level knowledge about iOS and macOS software application development. It’s okay to host lists of components/libraries for certain tasks. But these things change fast, and I cannot keep up with maintaining a list of libraries by myself.

I believe manual curation of knowledge is the only way to make starting application development feasible. Googling will only bring up popular results; but personal recommendations may provide a totally different angle.

So here’s to the next step in my grand scheme to empower Cocoa developers on every level, from code to marketing and lifestyle choices.

My personal website at christiantietze.de will gradually transition to an overview about all my projects. There was no headquarters for my apps until now. My personal website will now become such a place, including “press releases” and update announcements. Stuff my app business customers might be interested in, but programmers, not so much.

FatSidebar View Component for macOS Released

One important user interface part of my latest top-secret project involves a sidebar of buttons. Like a regular toolbar, but taking up less space for chrome, looking more flat, and the user should be able to create toolbar buttons herself.

So while I was mostly sick at home for the last couple weeks, I spent my time cobbling this together. With drag and drop reordering and all.

Find FatSidebar on GitHub!

I have never written my own custom view component from scratch before. I helped improve KPCTabsControl for Swift 3 when I created TableFlip last year. And of course I participated in a lot of smaller open source projects, too. But I never started from scratch, and that was cool.

Also fun: creating the library’s own “logo”. Made it feel so much more official.

What’s cool about writing a new thing from nothingness is that I had no clue what to do and how to start. This component turned out as rather adventurous mental gymnastics because I had to leave the paths of application development I know so well. I still don’t know all the answers; what are best practices? Get something colorful on screen? Customize drawRect and draw boxes and placeholders? Partition the view into sub-components using Auto Layout from the get go? Is drawing text better handled by NSTextField labels than NSAttributedString.draw(in:) or is the overhead too much? (I still don’t know the best answer for this.)

Anyway! I ended up putting this together as a library with sample app. There are some unit tests for inserting items into the “fat sidebar”, but otherwise I find the drawing and layout related code to be absolutely hideous. Cannot come up with improvements on that front that go beyond cosmetics, though. Maybe later, with more experience.

Non-Obvious Swift: Defer

The following code works as expected:

class FooCollection {
    private var items = [Foo]()

    func removeAllItems() -> [Foo] {

        defer { items.removeAll() }
        return items
    }
}

But do you know what “expected” means in this case?

As a reader, you assume the author had an intention. You look for the mens auctoris and are an overall benevolent reader, I hope. Presupposing said intention, you may assume that it does something special if you put the call to items.removeAll() in a defer block.

The removeAllItems method returns an array of items. If the internal collection was empty when the return statement is reached, that’d be pointless, wouldn’t it? Since your benevolent, you assume that the author isn’t stupid and that it does indeed return a non-empty collection in some cases.

Say the author had added a documentation line:

/// - returns: Array of items that were removed.
func removeAllItems() -> [Foo] { // ... }

Now that should tip the scale! So the internal collection of items is returned and afterwards emptied. Aha! How clever!

Ze true connoisseur of Swift appreciates ze brevity of defer

As a critical reader, you should be able to solve the puzzle and call the author names. Because, why make it so non-obvious to the reader? Why the guessing that either requires manual (or unit-) testing or the Swift doc (and trust in its truth) to verify the assumptions?

I was curious about the outcome of this approach so I just tried it before writing this up. Then I deleted the """clever""" code and replaced it with what I had before:

class FooCollection {
    private var items = [Foo]()

    func removeAllItems() -> [Foo] {
        let removedItems = items
        items.removeAll()
        return removedItems
    }
}

I prefer this any day. I hope you do, too.

Setting the Line Height of a NSTextView

NSTextView (and UITextView for that matter) have a defaultParagraphStyle attribute where you can set the text’s line height. That works swell – if you display text statically. Once the user can enter something, you can run into trouble:

  • If the user adds text in the middle of an already laid-out line of text, the paragraph style is retained.
  • If the user writes at the beginning of the line, the line height info gets lost.

This is what happens when you type at the beginning of a line

It’s your usual RTF nightmare. I know this behavior from rich text editors; and I developed my own way to make sense of it in the process. It might not be what is really going on, but it’s a good heuristic: it’s just like the opposite of making a word bold, placing your cursor after that word, type, and get more bold text. There, the “bold text” information is carried on. The cursor inherits this info from the character left to it. But if you start at the beginning of a line, your cursor will not inherit what comes afterward. And since there is nothing before its position, it starts with empty info, and thus empty line height settings. Since the whole paragraph is affected by this, the latest change wins. Beginning to type at the beginning of a paragraph with empty paragraph settings removes them from what comes afterwards.

So this might not be The Truth, but it helps me deal with shitty software. I don’t want to write shitty software, though, so I look for ways out of this. I don’t intend the user to change paragraph settings; I want the text view to have a certain look and feel no matter what gets pasted or typed in it.

Hunting for Core Text/TextKit callbacks, NSTextStorageDelegate seems to provide a good customization point:

func textStorage(
    _ textStorage: NSTextStorage, 
    didProcessEditing editedMask: NSTextStorageEditActions, 
    range editedRange: NSRange, 
    changeInLength delta: Int
) {
    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.lineHeightMultiple = 2.0
    textStorage.addAttributes([NSParagraphStyleAttributeName : paragraphStyle], range: editedRange)
}

Of course it makes sense to store the global paragraphStyle once and re-apply it here. I don’t know if this is the best place to put it, though. Re-applying all the NSAttributedString settings while typing might not perform best.

Also, this is affecting the “rich text representation” of the text. If you copy the result and paste it into TextEdit, say, the text will look the same, line height settings and all.

You can override the pasteboard representation to be “plain text” only in order to remove the style info and thus have it behave like the “Paste and Match Style” command from the “Edit” menu automatically.

Again, I don’t know if this is the best way to do this.

What I’d expect to create instead:

  • a text view with a “plain text” representation by default (the model)
  • typesetting customizations that only affect what is visible on screen (the view)

I imagine this to be like HTML code/browser rendering, not like WYSIWYG. What you type is not what you see. Just what you’d expect a source code editor to be like.

I’ll keep you posed as I dive deeper into TextKit and stuff.

How to Make ReSwift Actions Undoable with NSUndoManager

I wrote about using NSUndoManager + ReSwift with a Middleware. You could think of the resulting UndoMiddleware as some kind of observer of events that pass the ReSwift.Store and which puts the opposites of incoming actions on the undo stack. Why a Middleware? Because making an action undoable is a side effect.

The Middleware wasn’t exactly straightforward. It took a bit of type wrapping and boilerplate code. A “context provider” made parts of the current app state and model available to compute the opposite action. Without this context, the Middleware couldn’t know what was expected.

Today I came up with something shorter: an action creator. It works well because the actions in my current project are simple and easily reversed.

Instead of dispatching an action like this:

store.dispatch(CreateFoo(id: 1))

… you create the opposite of the action where you already do have knowledge about the context:

let creation     = CreateFoo(id: 1, content: "...")
let undoCreation = DeleteFoo(id : 1)
store.dispatch(undoable(creation, opposite: undoCreation))

Of course it takes more effort to compute it the other way around because you have to fetch the current content before you delete (that’s what the context provider of my Middleware did, too):

let id = // ...
let oldContent = foo(withId: id).content
let deletion =     DeleteFoo(id: id)
let undoDeletion = CreateFoo(id: id, content: content)
store.dispatch(undoable(deletion, opposite: undoDeletion))

Chances are you have a lot of the pieces of the puzzle to assemble the “undo” action in the service object that dispatches the original action. In contrast, the Middleware knew nothing and thus had to depend on another source of information for everything.

The undoable action creator is very simple, after all:

public func undoable(_ action: Action, opposite: Action?)
    -> (AppState, DefaultStore)
    -> Action?
{
    return { (appState: AppState, store: DefaultStore) -> Action? in
    
        if let undoAction = opposite,
            
            // Replace this with something useful in your app:
            let undoManager = getUndoManagerFromSomewhere() {
            
            undoManager.registerUndo(withTarget: store) { store in
                store.dispatch(undoable(undoAction, opposite: action))
            }
        }
    
        return action
    }
}

This assumes symmetry of actions: inside the registerUndo block, undoable is called again, only the other way around, to setup what “redo” should be like. If your original action is not what you want to use for redoing, then you need to put that in somehow.

This is the case in my app where DeleteFoo creates a pending file change that ends with dispatching DeleteFooCompleted. The opposite of DeleteFooCompleted is CreateFoo – but the opposite of CreateFoo is DeleteFoo, not DeleteFooCompleted, so I put a mapping in between:

public func redoable(basedOn action: Action) -> Action {
    switch action {
    case let action as DeleteFooCompleted:
        return DeletingFoo(id: action.id)

    default:
        return action
    }
}

public func undoable(_ action: Action, opposite: Action?)
    -> (AppState, DefaultStore)
    -> Action?
{
    return { (appState: AppState, store: DefaultStore) -> Action? in
    
        if let undoAction = opposite,
            let undoManager = getUndoManagerFromSomewhere() {

            // Original trigger might be a 'completion' event that has to be
            // "redone" using a 'starting' event.
            let redoAction = redoable(basedOn: action)

            undoRegistrar.registerUndo(withTarget: store) { store in
                store.dispatch(undoable(undoAction, opposite: redoAction))
            }
        }
    
        return action
    }
}

And that’s it!

The biggest problem is to obtain a reference to the main window’s UndoManager instance. You can inject it once but not replace it later, which I would have needed, so I end up with a getter here, which I don’t like a lot; you might be fine with providing a custom UndoManager instance during setup, though! In NSDocument-based apps, where each document has its own window with its own undo manager and probably its own store instance, it’ll be pretty easy.

Handle Pending File Changes with ReSwift as Your Backbone

Automatic saving of changes in some user interface component to a file should be handled differently when you employ ReSwift.

Your UI tells the app it finished editing. Then a reducer enqueues a pending file change.

In short, you have to extract the state information from the “save file” action and store it in the overall app’s state somehow. I append these to a collection of PendingFileChanges, a ReSwift.StateType that is part of my overall app state.

(This is a follow-up to my previous musings on the topic.)

“Save file” has the state info of “which file” and “what contents”. In order to enqueue multiple changes to the same file, add a UUID to each file change to identify the event:

struct FileContentChange {
    let url: URL
    let content: String
    let uuid: UUID
}

Instances of this type are enqueued with the PendingFileChanges substate. I used real FIFO queues at first and solely relied on the order, but later switched to simple arrays. I’ll tell you why in a minute.

struct AppState: StateType {
    var pendingFileChanges: PendingFileChangesState = .empty
}

struct PendingFileChangesState: StateType {

    static var empty: PendingFileChangesState {
        return PendingFileChangesState(fileContentChanges: [])
    }
    
    public fileprivate(set) var fileContentChanges: [FileContentChange]

    public var nextFileContentChange: FileContentChange? {
        return fileContentChanges.first
    }

    public mutating func insert(fileContentChange: FileContentChange) {
        fileContentChanges.append(fileContentChange)
    }

    public mutating func remove(fileContentChange: FileContentChange) {
        guard let index = fileContentChanges.index(of: fileContentChange) 
            else { return }
        
        fileContentChanges.remove(at: index)
    }
}

Some long-running service object will listen to changes to this substate and perform the necessary writes periodically.

To simplify the setup, make the resulting ChangeFileContents service object a ReSwift.StoreSubscriber; now it’ll receive updates to the app state from your store. Cache the last received (and thus pending) change in the service so you can make the operation asynchronous and allow more incoming state updates without issuing to overwrite the file time and again with the same stuff.

When it finishes a write operation, it in turn dispatches an action so the fitting item is removed from the queue.

Here’s a sample service wireframe:

typealias DefaultStore = Store<AppState>

class WriteFileChanges: StoreSubscriber {
    let store: DefaultStore

    public init(store: DefaultStore) {
        self.store = store
    }

    fileprivate(set) var lastChange: FileContentChange?

    public func newState(state: PendingFileChangesState) {
    
        // If the state update shows the queue is empty, 
        // reset the cache.
        guard let change = state.nextFileContentChange else {
            lastChange = nil
            return
        }
        
        // Skip identical, unprocessed updates.
        guard change.uuid != lastChange.uuid else { return }
        
        // Set the cached value to prevent duplicate changes.
        lastChange = change

        delegatePerformingTheFileWriteOperation() { success in
            if !success { 
                // TODO: handle error :)
            }
            
            store.dispatch(CompletingFileContentChange(change))
        }
    }
    
    fileprivate func delegatePerformingTheFileWriteOperation(
        completion: (Bool) -> Void) {
        
        // Use FileManager or String.write(toURL:) etc.
        
        completion(true)
    }
}

So you end up with WriteFileChanges as a service that processes a part of the PendingFileChangesState queue. To let the app know when it has finished, i.e. let a reducer remove the entry from the pending changes queue, it dispatches a CompletingFileContentChange action. I leave this simple wrapper as an exercise to the reader.

Now that you know all of the code, here’s why I ditched queues at first. With queues, I relied on the order of elements and used equality checks in the WriteFileChanges service to prevent doing the same operation twice. Before the UUID, enqueuing 2 equal FileContentChange objects resulted in the first one being processed, then popped from the queue after completion – but then the second, identical object would never be processed. Now that I think of it, since adding the UUID, the issues I had with queues is solved. So it’d actually be a better idea to use a queue instead of an array to be clear about the order. Plus make it a UniqueElementQueue or similar and add equality checks before adding elements so you don’t end up enqueuing the same thing twice while lifting this detail into the type itself.

A queue-based approach is a good idea because most apps will rely on the order of file change events. If you have write and delete operations, you will want to put both into the same queue, too, by the way, and introduce a common type for FileContentChange and FileRemoval, say.

Having written that down, I’m going to change my implementation from array to queue with the UUID and see where this leads first thing next week.

Recording of Wednesday's Webinar

Sadly, the recording doesn’t contain the webcam stream. I find videos like this pretty hard to follow. Especially if the speaker isn’t native English, then it can be quite a pain sometimes. I hope it’s not too bad in this case!

I promised not to distribute any follow-up material until next week so that webinar attendees have early access.

But you can get a 20% discount on “Make Money Outside the Mac App Store” by using the coupon code MORECONTROL, good until March 31st!

Browse the archive

Subscribe via RSS