Parse Boolean Search Expressions in Swift

Ever wanted to implement a full-text search in your app? Didn't find a boolean search expression parser that works? Look no further! For the initial release of my note-taking app The Archive I had to create a couple of open source libraries that I have yet to talk about. Today, I want to show you my search expression parser. It powers the app's Omnibar to find notes quickly using simple boolean expressions.

Continue reading …

Fixing Ruby ncurses Unicode Character Display on Linux Terminals

A little side-project of mine is a role-playing game written in Ruby that runs in the terminal and uses Unicode/ASCII characters instead of bitmap pixel graphics. In my personal tradition of these kinds of side projects, this is called TermQuickRPG. It's a work-in progress, so there's not a lot to do in the sample game at the moment.

Continue reading …

How to Fix fileReferenceURL() to Work with NSURL in Swift 3 and Swift 4

I am upgrading the code base of the Word Counter to Swift 3. Yeah, you read that right. I didn't touch the Swift code base for almost 2 years now. Horrible, I know – and I'm punished for deferring this so long in every module I try to convert and build. One very interesting problem was runtime crashes in a submodule I build where URLs were nil all of a sudden. This code from 2015 (!!) used to work:

Continue reading …

Remove Trailing Whitespace in TextMate 2 Code Files

I still use TextMate for some things: editing documents quickly, scripting in Ruby, navigating project folders of foreign code bases (especially when they're not using my main language so I could use Xcode, e.g. Java projects), and finding and replacing text. But it always bugged me that when I move around code and indent and outdent and whatnot, that sometime lines with nothing but whitespaces would be saved. Or I'd combine stuff and have 10 trailing spaced all of a sudden. I do show invisible characters, but I don't want to pay attention to that kind of stuff when I'm coding.

Continue reading …

ReSwift Custom Diffs and Enqueued State Updates

Vinh Nguyen found that his ReSwift status updates became slow.

  1. There were too many subscribers.
  2. Objects would react to state updates by dispatching a new action immediately. (ReSwift action dispatching happens synchronously.)

His app state ends up containing a lot of objects in a 3-level hierarchy that mimicks the hierarchy of view components on screen. In a drawing or otherwise canvas based graphics app, it seems. It doesn't make sense to have each objects on the canvas responds to state updates when one other object updates on screen. Instead, you'll want to at least minimize the amount of updates that get passed through.

Vinh implemented a custom diff or "delta update" for the 2nd level in his 3-level hierarchy of objects because they were few enough to be performant during state updates, and could easily manage their child objects.

Read about his discovery of state update bottlenecks on his blog.

He solved the second problem, newState callbacks triggering the dispatch of another action, by enqueuing the dispatch in an asynchronous block on the main queue, which is the queue ReSwift uses:

class ObjectView {
    func newState(state: ObjectState) {
        // ...
        if conditionThatTriggersAnAction == true {
            DispatchQueue.main.async {
                store.dispatch(Action())
            }
        }
    }
}

Sure, this enqueues the action dispatch until the current execution is finished. But you have to take care about other actions being dispatched in between now, and if that is a problem. (E.g. another subscriber type reacting to the same state update with another action.)

I had prefered another solution initially: subscribe to updates in the top level Canvas object, then delegate down the view hierarchy as needed. Every sub-component that wants to fire an action tell the Canvas about this, which enqueues the actions, and then processes the queue after all sub-component updates are finished. A bit like in game development where the game loop ensures there is just 1 point of action handling per run. But then again, Vinh's approach does exactly that: it enqueues action dispatching until later, ensuring the current run loop run isn't interrupted. Also, my approach to delegation would make everything just so much more complicated in the app code.

I wonder is it'd be beneficial if the ReSwift store operated on a high priority queue that is not the main queue all the time. Then you can dispatch actions synchronously from view components on the main queue, waiting for the result, or asynchronously.

I will have to think more about the consequences of an approach like this before I suggest anything to anybody, though. I don't do a lot of concurrent programming in my apps, and when I do, I contain it very strictly; on the downside, I don't have developed any instinct regarding implications of using multiple queues.