Weblog entries 2017

vultr 2017-02-21.png

This page contains an uploaded file:

vultr 2017-02-21.png

No summary was provided for this file.

uistackview playground 2017-04-11.png

This page contains an uploaded file:

uistackview playground 2017-04-11.png

No summary was provided for this file.

main storyboard file base name 2017-02-03.png

This page contains an uploaded file:

main storyboard file base name 2017-02-03.png

No summary was provided for this file.

Linode login 2017-02-21.png

This page contains an uploaded file:

Linode login 2017-02-21.png

No summary was provided for this file.

2017-09-17 Replacing NSTimer in Swift 4

For repeated calling of a function, the Timer class is available (used to be called NSTimer). So perhaps you had the following code in your Swift 3 project:

    private var timer: Timer?
    override func viewDidAppear(_ animated: Bool) {
        self.timer = Timer.scheduledTimer(
            timeInterval: 1.0, target: self,
            selector: #selector(self.timerAction),
            userInfo: nil,
            repeats: true)
    func timerAction() {
        // Do something

When you move your project to Swift 4 (via Xcode 9), then first you get the following warning:

    The use of Swift 3 @objc inference in Swift 4 mode is deprecated. Please address deprecated @objc inference warnings, test your code with “Use of deprecated Swift 3 @objc inference” logging enabled, and then disable inference by changing the "Swift 3 @objc Inference" build setting to "Default" for the "blah" target.

You can fix this warning by updating the project settings and update the code as follows:

    @objc func timerAction() {
        // Do something

For some reason, I don't like seeing that @objc in my projects. There's an alternative, and that's not to use Timer at all, but instead move to GCD:

    private let timer = DispatchSource.makeTimerSource()
    override func viewDidAppear(_ animated: Bool) {
        timer.schedule(deadline: .now(), repeating: 1.0)
        timer.setEventHandler {
            DispatchQueue.main.sync {

Have fun with Swift 4 :)

2017-07-25 Swift dictionary keys to array

The following code can be pasted into a Swift playground, and demonstrates how you can get a mutable array of (a copy of the) dictionary keys.

    let dict = ["Fritz": "Senior Engineer",
                "Mary": "Director of Safety",
                "John": "VP of this and that"]
    var keyArray: [String] = dict.keys.map { $0 }
    if let index = keyArray.index(of: "Fritz") {
        keyArray.remove(at: index)

If you don't cast to an array of Strings, you'll get the following error:

    error: value of type 'LazyMapCollection<LazyMapCollection<Dictionary<String, String>, String>, String>' has no member 'remove'

2017-06-07 Make a list of files left after installing software

Sometimes, Mac software is distributed as an installer. Potentially that leaves a bunch of files strewn all over your Mac its filesystem. One tip is to run the following command before installation:

 $ find -x . /  > before.txt

Then install the software, and run it once. Quit, then run the following two commands:

 $ find -x . /  > after.txt
 $ diff before.txt after.txt > filelist.txt

Now open the filelist.txt and you'll see a rough list of all installed files. Both as a result of the installation, but also takes into account whatever the software wrote in your ~/Library folder.

2017-06-06 Always leave a view in a stackview

When you hide/unhide an element in a UIStackView, it will nicely animate. However when you hide the only element in the stackview, the animation will go wrong. To see what happens, run the following project:


Click the "Toggle Visibility" button. Then tap the "Add dummy view" button and try again.

2017-05-29 Creating a Swift module

When creating a custom view, I find it very useful to make it into a framework and include an example project. This enables quickly iterating over the new component. Plus, when you're done, it's very easy to import the result into other projects. To set this up, take the following steps:

  • Create new project, and choose Cocoa Touch Framework
  • Type some name that reflects a library name such that "import yourlibname" looks logical and good
  • Create a new Swift file, and add your code there
  • Then go to menu File -> New -> Target and create a Single View Application
  • Name it YourlibnameExample or something
  • Select the project, then the new target, and in the Embedded Binaries section, click the plus
  • Select the previously created framework, and click Add
  • Then edit the new ViewController and type "import yourlibname"
  • Then instantiate a class from your framework somewhere; no errors should occur

2017-05-09 Check PDF file header with Swift

Here's a little Swift playground that shows how you can check whether a Data object (for example from a file) is a PDF. It's done by checking the first couple of bytes.

    import UIKit
    // http://stackoverflow.com/a/26503955/1085556
    func dataWithHexString(hex: String) -> Data {
        var hex = hex
        var data = Data()
        while(hex.characters.count > 0) {
            let c: String = hex.substring(to: hex.index(hex.startIndex, offsetBy: 2))
            hex = hex.substring(from: hex.index(hex.startIndex, offsetBy: 2))
            var ch: UInt32 = 0
            Scanner(string: c).scanHexInt32(&ch)
            var char = UInt8(ch)
            data.append(&char, count: 1)
        return data
    struct HeaderError: Error {
    // http://stackoverflow.com/a/17280876/1085556
    let smallestPDFasHex = "255044462D312E0D747261696C65723C3C2F526F6F743C3C2F50616765733C3C2F4B6964735B3C3C2F4D65646961426F785B302030203320335D3E3E5D3E3E3E3E3E3E"
    let data = dataWithHexString(hex: smallestPDFasHex)
    let headerRange: Range<Data.Index> = 0..<4
    let header = data.subdata(in: headerRange)
    guard let headerString = String(data: header, encoding: .ascii) else {
        print("Header not found")
        throw HeaderError()
    if headerString == "%PDF" {
        print("It's a PDF")
    } else {
        print("It's NOT a PDF")

2017-04-11 UIStackView playground

Here's a nice way to play with a UIStackView. Copy and paste the following code into a playground, and next to the final line, click the screen icon to permanently show it. Then adjust the parameters of the playground where necessary.

    import UIKit
    var view = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
    view.backgroundColor = UIColor.yellow
    let label1 = UILabel()
    label1.text = "label 1"
    let label2 = UILabel()
    label2.text = "label 2"
    let spacer1 = UIView()
    spacer1.backgroundColor = UIColor.green
    spacer1.translatesAutoresizingMaskIntoConstraints = false
    spacer1.widthAnchor.constraint(equalToConstant: 3).isActive = true
    let spacer2 = UIView()
    spacer2.backgroundColor = UIColor.gray
    let stackView = UIStackView(arrangedSubviews: [label1, spacer1, label2, spacer2])
    stackView.distribution = .fill
    stackView.axis = .horizontal
    stackView.translatesAutoresizingMaskIntoConstraints = false
    stackView.spacing = 20
    stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
    stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
    stackView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
    stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true

The result should look something like this:

uistackview playground 2017-04-11.png

2017-04-07 Stopping autoplaying videos

There's a larger and larger number of websites that auto-play completely unrelated videos when opening a page on their website. In my opinion, a very user unfriendly business.

Thankfully Firefox has an extension for this, FlashStopper: https://addons.mozilla.org/en-US/firefox/addon/flashstopper/

Before and after installing, open for example this page on the Reuters website: http://www.reuters.com/article/us-twitter-lawsuit-idUSKBN1782PH

2017-04-04 UITextView with placeholders

For my current project, the user needs to select a template from a list. The template contains a number of placeholders where text needs to be filled in, and further editing needs to be done.

I've created an example Xcode project on GitHub which shows how this can be done:


2017-02-21 Linux VPS with TeamViewer

Here are my short notes on creating a Linux VPS (virtual private service) which can be remotely accessed via TeamViewer. I prefer TeamViewer over other ways of remotely accessing a desktop, because it works cross-platform and through NAT and firewalls.

The big problem is often that a Linux VPS doesn't have a virtual graphical card. For remote access to the GUI, most VPS providers advise VNC while I prefer TeamViewer.

I've tried a number of Linux distributions on a number of VPS providers. The instructions below fail on VPSes at Scaleway or DigitalOcean, but the combination of Fedora 25 and Linode or Vultr made this all very easy.

First of all, register or log in at Linode or Vultr, and create a VPS. You'll need at least 1 GB of memory.

After it's started, log in via SSH as root and do the following:

  # yum -y groupinstall "Fedora Workstation"

Then get the TeamViewer download URL and install the package:

  # wget "https://download.teamviewer.com/download/teamviewer.i686.rpm"
  # yum -y install ./teamviewer.i686.rpm

Next reboot, make sure the GUI starts:

  # systemctl set-default graphical.target

If your VPS runs at Vultr, disable Wayland. Edit the file /etc/gdm/custom.conf and remove the comment for the line WaylandEnable=false so GDM uses X.org. Linode already has this correctly set.

Then, add a user for yourself:

  # useradd -m -U mynewusername
  # passwd mynewusername

Add the new user to the sudoers, and reboot:

  # visudo
  # reboot

If you're on Linode, open remote access via glish, which is Linode's way of giving you graphical access to your VPS, through your browser. Log into the Linode management console, click on the node, then in the tab Remote Access, click the link "Launch Graphical Web Console".

If you're on Vultr, open remote access by navigating to the Instances tab in the management console, then click the three dots at the right of your server and in the menu, click "View Console":

vultr 2017-02-21.png

You should see the graphical Linux login screen. In the top left corner, set shell to "Gnome Xorg" (this is important!) and then continue to log into Gnome.

Linode login 2017-02-21.png

In Gnome, start TeamViewer. Check the three boxes to enable remote access. You'll need to provide TeamViewer username/password, as well as click the link in the email you'll get, to confirm adding this VPS to your TeamViewer device list.


Note: a current disadvantage is that you're constricted to pretty low resolutions. On Linode, you can't set the resolution to something bigger than 1280x768. On Vultr, the maximum is 1280x1024.

2017-02-03 Create your own laptop battery test

Recently I wanted to test how long the battery of my 2013 MacBook Air lasts. The quickest solution I found, is as follows:

  • Download Firefox.
  • Get the iMacros for Firefox extension.
  • Make a list of, say, ten websites.
  • After installation, click the iMacros button so the sidebar appears.
  • Open a new tab for the purpose of recording the macro.
  • Click record.
  • Type in these ten sites. Just type the URL in the address bar. Clicking anywhere will often result in failed playback. Searching for a keyword in Google is fine, though.
  • Stop recording and edit the macro. Add the line "WAIT SECONDS=5" a couple of times, to simulate the time spent reading.
  • Play the macro once to make sure you won't have errors occuring during playback.
  • In the settings of iMacros, set playback speed to slow.

Now to test the battery:

  • Click on the battery icon in the menubar and click "show percentage". It should obviously show 100% at this point because we want to start fully charged.
  • In System Preferences, turn off the screensaver. Under Energy Saver, set "turn display off after..." to "Never".
  • Note the current time somewhere, then remove power cord.
  • Set the screen brightness to something reasonable, like 75%.
  • Set the loop field to 10000 or some other high number.
  • Click the Play Loop button.
  • Every half hour, have a look at the battery level and write it down.

So this is my ghetto battery test. It's a bit rough around the edges, but should give you an idea of how many hours the battery lasts. Don't take the results too serious, this is meant to get a ballpark figure.

2017-02-02 Swift app without Interface Builder

Here's an example of an AppDelegate.swift, for those who don't like Interface Builder:

    import UIKit
    class AppDelegate: UIResponder, UIApplicationDelegate {
        var window: UIWindow?
        func application(_ application: UIApplication,
            didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
            self.window = UIWindow(frame: UIScreen.main.bounds)
            let vc = ViewController()
            let nc = UINavigationController(rootViewController: vc)
            self.window?.rootViewController = nc
            return true

Remove the Main.storyboard file from the project. And in the Info.plist of your project, remove the entry called "Main storyboard file base name:

main storyboard file base name 2017-02-03.png

2017-01-12 Finder shortcuts

I couldn't find a one-page PDF with all macOS Finder shortcut keys. So I made one: Finder shortcuts.pdf. Here is the original, so you can adjust to your liking: Finder shortcuts.xlsx. Both are licensed under the Creative Commons Attribution 4.0 International License.