Stuart Breckenridge

Reducing Bundle Size and Improving Extension Performance

The today extension of The FFI List displays the number of registered FFIs broken down by their entity type. It’s fairly simple, but I made a few mistakes when putting it together:

  1. I copied the sqlite database into both the main app and the extension; and,
  2. The code to run queries on the database to obtain statistics was part of the extension.

The net effect was that the bundle size was approaching 180MB (two 80MB databases). In addition, performance of the extension was haphazard: I had reports, and had seen myself, instances where the extension returned a seemingly random count of total database entries. What’s worse was that I couldn’t debug the problem. No errors were raised, the underlying data was intact, and I couldn’t reproduce the problem with any regularity. It also took around upwards of four seconds for the queries to run.

In the upcoming v2.1 release, I’m happy to say these issues are fixed.

First, the sqlite database is longer embedded in both the main application and the extension. The bundle size is once again under 100MB.

Second, to make sure that the extension was able to show statistics like it did before, I created a Statistics.plist file and as part of the build process, I run some sqlite queries and then populate the data into the plist file like so:

sponsors=$( sqlite3 _YOUR_DATABASE_ "select count(ZENTITYTYPE) from ZFFIENTITY where ZENTITYTYPE = '01SP'")
/usr/libexec/PlistBuddy -c "Set 01SP $sponsors" "${TARGET_BUILD_DIR}/"

When the main app runs, it will copy the Statistics.plist file into the shared container:

let container = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.ffiinfo")?.appendingPathComponent("/Statistics.plist")
let stats = Bundle.main.path(forResource: "Statistics", ofType: "plist")
guard let containerURL = container else {
    return shouldPerformAdditionalDelegateHandling
guard let statsPath = stats else {
    return shouldPerformAdditionalDelegateHandling

if FileManager.default.fileExists(atPath: containerURL.path) {
    do {
        try FileManager.default.removeItem(atPath: containerURL.path)
        try FileManager.default.copyItem(atPath: statsPath, toPath: containerURL.path)
    } catch {
} else {
    do {
        try FileManager.default.copyItem(atPath: statsPath, toPath: containerURL.path)
    } catch {

The extension then displays the available data from the plist when it exists in the container. This improves performance from several seconds to instantaneous as the extension is no longer running any database queries.


Manton Reece and Brent Simmons:

We — Manton Reece and Brent Simmons — have noticed that JSON has become the developers’ choice for APIs, and that developers will often go out of their way to avoid XML. JSON is simpler to read and write, and it’s less prone to bugs.

So we developed JSON Feed, a format similar to RSS and Atom but in JSON. It reflects the lessons learned from our years of work reading and publishing feeds.

I try to avoid XML when I can, so I’m obviously very pleased to see a JSON standard appear for feeds.

I’ve created a JSON feed for this site which is available here. I’ve also uploaded my current Jekyll template to GitHub.

Now I just need to find a reader that supports the JSON feed spec!

An Unexpected Win

Via the BBC:

A security researcher has told the BBC how he “accidentally” halted the spread of ransomware affecting hundreds of organisations, including the UK’s NHS.

The man, known online as MalwareTech, was analysing the code behind the malware on Friday night when he made his discovery.

He first noticed that the malware was trying to contact an unusual web address - - but this address was not connected to a website, because nobody had registered it.

So, every time the malware tried to contact the mysterious website, it failed - and then set about doing its damage.

MalwareTech decided to spend £8.50 and claim the web address. By owning the web address, he could also access analytical data and get an idea of how widespread the ransomware was.

But he later realised that registering the web address had also stopped the malware trying to spread itself.

Stopping the spread of the ransomware was an incredibly lucky side effect of purchasing the domain name. However, any win in this scenario — it’s the largest ransomware spread I can recall, and certainly the most shameless (attacking a health service) — is a win worth taking.

Selling My Late 2013 iMac

Update 2017-05-07: Sold.

I am selling my late 2013 iMac. It’s a custom build (specs below) and you can declare an interest on Carousell. It’s in perfect working order.


  • 3.5Ghz Quad-Core i7 processer
  • nVidia GTX 780m graphics card (4GB)
  • 16GB RAM
  • 3TB Fusion Drive
  • Keyboard & Trackpad
  • Original packaging (see pic below)
Original Packaging