RSSAmplifier

Blog

annema.me

This is a longer description about your blog.

annema.meRSS feed ↗42 posts

Latest posts

OWE on the GL.iNet Flint 3

For my work at IPinfo I needed an open Wi-Fi network to test against. Having learned of the existence of Opportunistic Wireless Encryption (OWE) and that OpenWrt supports it , I wanted to have one. OWE encrypts traffic on open networks without requiring a password. Clients ( Apple , Android ) that support OWE encrypt their traffic. Lack of encryption was always the big drawback of open networks.…

Configure GL.iNet GL-BE9300 (Flint 3) on KPN fiber

Backstory Up until a few days ago my main Wi-Fi router was an Apple Time Capsule. It's one of the latest models but still this thing is old . Apple discontinued the product line in 2018 but I probably bought it in 2013, maybe 2014. That makes it over 10 years old. It survived 3 NYC apartments, a move back to The Netherlands, being stored in an attic for a while, dusted off and then 2 more houses.…

Get notified when a GitHub action completes

Often I’m waiting to merge a PR until all of its checks have passed. While I do my best to keep checks as fast as possible they still take long enough that I’m not going to wait for them to finish. I start something new while I wait. Frequently I then forget to merge the PR because I’m completely caught up in the next thing. This is even worse for PRs where I’m testing changes to the GitHub…

Converting ISO country codes to country names using Locale

Because IPinfo's open API always returns country codes, I needed to convert them to country names for better address formatting. For example, 1.1.1.1 returns AU for Australia. The authenticated tiers (free Lite and paid Core / Plus ) have both codes and names, but the open API doesn't. At first I hoped this would do the trick: let postalAddress = CNMutablePostalAddress ( ) postalAddress .…

What is bad behavior?

During my run I had a discussion in my head about bad behavior. What makes a behavior bad? Why is it bad? The discussion in my head started when I ran by an elephant path made by people, mostly kids, biking across the grass to get to the main bicycle path. I was annoyed by this because my community has asked people to stop doing it and I talk to my kids about it every time I see them do it. Even…

Accessing Swift Package Manager dependency versions at runtime

I was building a debug screen for an iOS/Mac app and wanted to display the version of a third-party dependencies managed by Swift Package Manager. My first instinct was to use an Xcode run script build phase to extract version information at build time, but I quickly ran into various code signing errors that made this approach unreliable. Especially because building for macOS triggered code…

Moving DNS from Cloudflare to Gandi using DNSControl

Current setup I'm in the process of moving this site to Europe. For the past couple of years annema.me was hosted on GitHub Pages. My domain registrar was dotster.com and DNS was done by Cloudflare. Historical context I registered annema.me with Dotster in 2011 because I worked at Sofa and they used Dotster. I later moved to Cloudflare for DNS since it made HTTPS easy. For years all I heard from…

Dynamic bundle identifiers in Xcode: Using xcconfig for different configurations

Generally in Xcode you have two configurations: Debug and Release. It's often a good idea to have a different bundle identifier for each configuration so that your debug builds don't replace the release builds on your device. Normal setup For a single target I usually start with three xcconfig files: Base.xcconfig , Debug.xcconfig and Release.xcconfig . Base.xcconfig is for build settings shared…

Detecting when an Android permission can only be granted via Settings

I was surprised to discover how easy it is, even when following the official Android permissions guide , to end up with a button that does nothing. Setting the stage: how it works on iOS On iOS CLAuthorizationStatus has 6 possible states to indicate what level of access a user has granted to their location: public enum CLAuthorizationStatus { case notDetermined case restricted case denied static…

New website

I wrote my last blog post in 2016 . Ever since I felt like I wasn't doing anything worth writing about. I was no longer enjoying myself as a software developer. I burned out. There were a lot of factors that contributed to my burnout but one of them was definitely that I no longer enjoyed the way I built software. Unfortunately it took years to gain the insight that I still enjoyed making…

Find time zones where it's currently a certain time

For a project I'm working I needed a function that returns the time zones where it's currently 9am. I generalized the function to be able to find time zones where it's currently any time. My Swift implementation was inspired by this stackoverflow answer , providing code for the same problem in Ruby. func timeZonesWhereItIs ( hour : Int , _ minute : Int = 0 ) -> [ NSTimeZone ] { let calendar =…

Gesture Recognizers in Swift

I wrote about using Gesture Recognizers in Swift for thatthinginswift.com . I ran into a couple of surprises using gesture recognizers in Swift. Nothing major, but definitely things to look out for. Head over to the article to read more about it. Nick is also looking for more contributors. If you're interested send a PR . If you need inspiration for topics take a look at issues 8 .

Ruby's tap method in Swift

Ruby has a nice method called tap , which I wanted to try and port to Swift. To learn what it does, let's take a look at Ruby's documentation : Yields self to the block, and then returns self. The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain. Yeah, right. I don't really know what that means. Googling yields…

The Builder Pattern in Swift

A while ago I wrote a post about implementing the builder pattern in Objective-C. Today we're going to do the same for Swift. In the previous post the end result was: Pizza * pizza = [ Pizza pizzaWithBlock : ^ ( PizzaBuilder * builder ] ) { builder . size = 12 ; builder . pepperoni = YES ; builder . mushrooms = YES ; } ] ; There is a couple of things that can be improved here: The syntax. I don't…

Configure your iOS app for multiple environments

Two weeks ago I wrote a post about cleaning up your application delegate with initializers . I eluded to a Configuration object in that post. I decided to make this two separate posts because they're different concepts that happen to work together. The Karma app has to run in 3 environments: Development, Pre-release and Production. We also have some secondary environments, like Test and Device,…

Clean up the application delegate with initializers

The application delegate has a tendency to become unwieldy. It provides a ton of callbacks to respond to about every possible state change of your app. The method that grows quickest is usually applicationDidFinishLaunching:withOptions: [citation needed] . From preloading content for a better experience, to configuration third party services, it all tends to end up in that same method. I've been…

Adopting a new programming language

Over the course of my short career I've had the opportunity to build production-quality software in many new languages. I like learning new languages. I think it makes me a better developer. My skill level is probably average in most of the languages I’ve worked with, but I've learned something useful from each and every one. Here's my approach to adopting a new language. Commit! There’s no use in…

Hour formatting with NSDateFormatter dateFormatFromTemplate

TLDR; Using NSDateFormatter's dateFormatFromTemplate:options:locale: for 12/24 hours? Use "j" instead of "h" or "H" for the hour format. Last week I started a fight with NSDateFormatter. I needed to format just the hour of an NSDate . Formatting hours is especially tricking because unlike any other date component, the same hour can be shown in two different formats, 12 hour with am/pm designator…

Builder and GCC Code Block Evaluation

My post about the builder pattern got great responses and a lot of people offered alternative solutions to the same problem. The most popular suggestion was to use GCC Code Block Evaluation without the separate builder object. Using the pizza example from the previous post it looks like this: Pizza * pizza = ( { Pizza * builder = [ [ Pizza alloc ] init ] ; builder . size = 10.0 ; builder .…

TDD - Classicists vs Mockists

A while ago I reread Martin Fowler's classic mocks aren't stubs essay . He does a great job of explaining the different schools of TDD. In summary it basically comes down to classicists, those that build the system from business models up and mockists who build the system from the UI down mocking lower level components that haven't been build yet. The essay got me thinking about which school I…

The Builder pattern in Objective-C

Learning Android and by extension Java has given me some new patterns to apply in my Objective-C code. The one that I'm most excited about is the builder pattern . The builder pattern is an object creation pattern that fits well with Java's syntax. I've seen some adaptions to Objective-C but they all directly copy Java's implementation directly and are not very idiomatic. Let's start off with what…

Android adventures #3 - Testing

Due to an injury I had to suspend training for my first half marathon for the remainder of the week. I found myself with some extra time yesterday morning. I decided to spend that time on trying to set up testing for the Karma Android app. Honestly testing on Android is about the same state as Objective-C when I started 5(?) years ago. At Karma we test most of our code (including our iOS app) but…

Android adventures #2 - The first crash

Last week we introduced bug fix monday's at Karma. The goal is to have a dedicated day to fix bugs that we usually don't have time for. Because, you know, features are better. In Android I've had a crasher for a while that falls into this category. With every release I classify it as a nice to have and end up not getting around to it. On the first bug fix monday I decided to tackle it. Problem is…

Android adventures #1 — Perform task on launch

I'm going to try and apply the Brent Simmons approach to Android development. This is the first installment. I need a way to do something when my Android app is launched. Most Google results I find are about getting notified when another app launches. I'm just interested in when my app launches because I need to load the user's authorization token from disk and create the session. I realize that…

The Pomodoro Technique

A while ago I started working with The Pomodoro Technique . I initially had my reservations but after using it semi-consistently for a couple of months I don't see myself going back. Pomdoro is a time management method named after the kitchen timer. The basic premise is that you decide on a task to work on, set the timer at 25 minutes and exclusively work on that task. When 25 minutes have elapsed…

Problems with iOS Push Notifications

Push notifications are a great way to keep users engaged with your iPhone app. The amount of applications that support them led me to conclude that supporting push notification must be trivial. After implementing them myself I'm left with the realization that it is most definitely not. Consider the Karma iOS app , we have a simple use case, when a push notification is delivered the user needs to…

Why I prefer testing with Specta, Expecta and OCMockito

Update August 2014 : Since writing this article, OCMock has released major version 3. Everything said about OCMock is based on version 2. If you're testing your Objective-C code (you should) you've probably heard of Kiwi and XCTest. Great! Do you like it? Awesome! You should switch to Specta and Expecta . Why? Keep reading. Uniform interface Specta provides one uniform interface that works for…

Initializing Objective-C classes with sane initial state

Because Objective-C has the concept of designated initializers , you have to ensure your classes are instantiated using sane initial state. Take for example a fictitious person class with the designated initializer initWithName: @implementation Person - ( id ) initWithName : ( NSString * ) name ; { self = [ super init ] ; if ( self ) { _name = name ; } return self ; } @end Now in a view controller…

Appreciating real world interaction

Moving to New York and having to quickly adept to a completely different culture has really opened up my eyes to a lot of beautiful interactions we encounter during our everyday lives. This inspired me to start realworlddetails.com to celebrate some of the great interactions we tend to overlook because of our busy lives. As a software user, and developer; I've come to enjoy consuming and creating…

Debugging Ember

While building the Karma customer dashboard I discovered several interesting ways to debug Ember apps. Some of these are my own, others I've taken from Tom Dale's excellent debugging Ember talk . Observers I don't need explicit observers often in production code but I do use them frequently for debugging. Adding an observer is very similar to a computed property: propertyObserver : function ( ) {…

CSS Markdown mark

I've been impressed with icons created in CSS3 and decided to have a go at it. As an experiment I took Dustin Curtis' markdown mark and made a version using only HTML and CSS. This is the result ( separate page ): Unfortunately, due to two issues in current browsers the icon is not pixel perfect. The M portion of the icon is rendered using the :before pseudo tag with a content attribute. By…

Changes to AppEngine's _from_entity

Both my blog and Enstore experienced a serious outage today. This was caused by a recent change to how App Engine initializes entities. The error was: BadArgumentError: Cannot use key and key_name at the same time with different values A common trick to detect wether an entity is loaded from datastore or not is to check if kwargs.get('_from_entity') == True: in the models __init__ method. Before…

My git setup

I have been using git since I started working on Cappuccino. Over time I've found several useful additions to my configuration that made working with it easier. Bash additions While working with git it's easy to get lost in branches, tags and commits. The bash completion script included with git helps to keep track. It's core functionality is autocompletion, but it can optionally show the current…

Announcing autonib2cib

Some time ago I posted a gist for a command line utility that automatically nib2cibs changed nibs. During the weekend I've rewritten the utility, making it more reliable with newly created nibs and nibs containing resources. I've also moved the code (all 100 lines of it) from the gist to it's own github repo . If you have a feature request or find a bug, please create an issue or even better, a…

Improving the Cappuccino Theme System

I've written about the Cappuccino theming system before[^1] and I have a confession to make, I don't like the current system. Let me clarify. Being able to change every visual aspect of a view is great, but currently it's too complex. It's complex because a it requires manual building, even during development. I should be able to make a change, refresh the browser and see the difference. Just like…

Cappuccino Custom Themes

A while ago I wrote a blog post about the basics of Cappuccino theming . Since then I've got a lot of questions about how to create fully customized themes. The first step in building your own custom theme is to create a theme descriptor. If you've built Cappuccino from source you can create one using the following command: capp gen -t ThemeDescriptor --build -F BlendKit [ Theme name ] If you…

NSConference MINI 2010 Sessions Online

This year, European developers had a hard time attending the WWDC , Apple's developers conference. The announcement was to late, forcing developers to arrange an entire inter continental trip in a relative short amount of time. There was also the pretty steep price and of course it was sold out within just 8 days! Luckily the community took care of us. The Mac Developer Network hosted a mini…

The future

Most of you probably already know, but for those who don’t; the company I work at, Sofa was acquired by Facebook . For reasons I can’t disclose I was not part of the acquisition. The last couple of weeks have been a very emotional and busy period. Over the course of two weeks I went from having a job I enjoyed, to moving to the Bay Area for a job at Facebook, to having no job at all. In other…

Programmatically Scroll a UIWebView

Ever wanted to scroll a UIWebView programmatically on the iPad or iPhone? Unfortunately Apple doesn't have a public API to do this, but there is a way. A UIWebView can execute any arbitrary javascript with stringByEvaluatingJavaScriptFromString: . Using this method we can easily scroll a web view like so: [ webView stringByEvaluatingJavaScriptFromString : @"window.scrollTo(0.0, 100.0)" ] ; It's…

The Basics of Cappuccino Theming

This is the second post of a series of posts about Cappuccino where I explain the subjects I talked about during my CocoaHeads Amsterdam presentation. The first post can be found here . Cappuccino and Cocoa have a lot of similarities, but there are some differences. Most prominent is probably Cappuccino's theming engine. Web developers are accustomed to a certain level of customization that Cocoa…

Objective-J Explained: Toll-Free Bridges

Last week I gave a talk on the Cappuccino frameworks during a Cocoaheads Amsterdam meeting. This post is the first in a series in which I'll explain several of the subjects I talked about during my presentation. I didn't have a lot of slides and they won't make much sense without explanation but for those that are interested you can download them here . All of the examples used in this post can be…

Welcome!

After some delay it's finally here. Welcome to my blog! I intend to post here whenever I learn something new and interesting. I don't have a specific subject in mind, but it will certainly have to do with usability, design and software. The reason for me to start this blog is that I like talking about things I learn. Of course it's also kind of mandatory to have a blog nowadays. I intend to talk…