Make Money Outside the Mac App Store now Available on Amazon

book cover

My e-book about creating and selling apps for Mac without the Mac App Store is now available on amazon.com if you prefer a print edition!

Why does print cost less?
The digital edition will be updated regularly with the latest Swift syntax. Further editions and major revisions are free for customers, too. I can’t do that with a print edition on your bookshelf, obviously. That’s why.

It feels weird, I know, because paper costs money and print book feel more precious. I’m making about 50% less with each sale, so there’s quite some cost involved printing the book. The feeling of physical good in your hand is part of the perceived value, and everyone would tell me I should factor that in, but I’m a bad businessman. It’s the right thing to do. Why should you pay more for something with less long-term value only because my costs are higher?

Move! Review at Softpedia

Teaser image

My humble work break timer Move! has been reviewed by Catalin Chelariu over at Softpedia. I didn’t find any Twitter account or anything to thank him, so here it is: thanks for the review!

Catalin had one wish, though:

However, it would be great if there was an option to postpone the break, as it simply may not be possible to interrupt your current activity in certain situations.

I have to say that I totally understand where this comes from – I used AntiRSI and similar software in the past which offered a postpone button. It was useful. But it was also opening the doors to hell.

So I’m sorry to say that if your job demands you to sit down for whatever reason, then Move! isn’t going to be your app. It’s made for everyone, because everyone needs to get up more often. 30mins really isn’t that bad. Some corporate environments don’t care about your health, though, so you may need to increase the work duration.

What I wish for this app myself is the ability to start a break early, i.e. when I have to leave the desk for a while. Or a setting for work hours, so that it doesn’t interfere me watching a movie after 9 p.m., for example.

Mind Node adds Tasks

screenshot of Mind Node

I love Mind Node for Mac. Now they added tasks. I think that’s weird, but I can see how this is useful for some people. You can devise plans and operate on them without having to export the outline to a task management application, for example.

It looks great and maybe I can use this for a little side-project which doesn’t really need traditional taks (which I put into OmniFocus) but could benefit from checking off items nevertheless.

Flow Controllers to Replace Segue-based View Transitions

Krzysztof Zabłocki wrote about the concept of “Flow Controllers”. Assimilating the concept, I imagine they’re similar to the bootstrappers I use during app launch, only Krzysztof says there’s just one initial flow controller after launch while the others are used when transitions need to take place.

Separating state from transitions is a higher-level goal of architecting apps – and is especially amiss in UIViewController-centered iOS apps. “Flow Controllers” encapsulate the change or transition. This includes setting up the view controller according to the presentation needs:

  • Configuring view controller for specific context - e.g. different configuration for an Image Picker shown from application Create Post screen and different when changing user avatar
  • Listening to important events on each ViewController and using that to coordinate flow between them.
  • Providing view controller with objects it needs to fulfill it’s role, thus removing any need for singletons in VC’s

The singleton Krzysztof talks about is the usual way app state is modelled.

Here’s a slightly modified example to illustrate how a flow controller manages transitions between view controller scenes with configureProgramsViewController, configureCreateProgramViewController, or similar:

func configureProgramsViewController(
        viewController: ProgramsViewController, 
        navigationController: UINavigationController) {
        
    viewController.state = state
    
    // Add button action callback to show the next scene
    viewController.addProgram = { [weak self] _ in
        guard let strongSelf = self else { return }
        
        let createVC = // recreate a view controller, e.g. from a Storyboard
        strongSelf.configureCreateProgramViewController(createVC, 
            navigationController: navigationController)
        navigationController.pushViewController(createVC, animated: true)
    }
}

The flow controller owns the state here and takes care of pushing view controllers onto the navigation stack. This will not work with segues. It’s a replacement for them.

ReSwift, Law of Demeter, and Another Level of Indirection

Teaser image

Benjamin Encz’s presentation “Unidirectional Data Flow in Swift” about ReSwift features global app state: there’s one AppState type that acts as the facade to model and navigation state which is the single point of truth of every state in the app. This is a game changer when you suffer from massive view controller syndrome. In this post, I’d like to show you how he envisions the state of an app and what a next step could look like.

Continue reading …

Events as Declarative State

Teaser image

I think I found something better than closures to handle events. Instead of dispatching closures that are themselves the changes that should be performed, simply declare the change.

enum Action {
    case ResizeBanana(BananaId, Size)
}

Now you need some kind of action handler, which Benjamin Encz calls “reducer” in his presentation “Unidirectional Data Flow in Swift”. Think of a list of reducers as a Chain of Responsibility only without the final consummation of the action. It is passed throughout the whole responder chain. Why reducer? Because they operate similar to the reduce function. The end result will be the combined result of all reducer’s mutations.

This is cool, because no component needs to know what such an action entails – none except the appropriate reducers.

If closures were great because where you type them you can see what is going on (more like “how” in my opinion), a simple action enum is even simpler, telling what should happen.

Works well with CQRS, I imagine. Will have to write a demo app using CQRS sometime to validate.

The current project is called ReSwift and code is available on GitHub.

Extending Types with a Conversion Factory: Where Should You Put It?

In a post about the Swift reflection API, I found the conversion code from a Bookmark struct to a Core Data object interesting. Let’s call the latter ManagedBookmark.

What puzzles me: which object should be responsible for the adaptation from one to the other?

  1. Bookmark converts itself to a NSManagedObject using a NSManagedObjectContext you also have to pass in. (That’s what Benedikt did in his post.)
  2. ManagedBookmark provides an initializer or other factory taking in a Bookmark and, as always with managed objects, a NSManagedObjectContext.

Option 2 is pretty clear. Using Bookmarks public interface, the managed object will set its attributes. This requires a NSManagedObject subclass wheras option 1 can work with a dictionary of values.

My main worry is that in option 1 Bookmark, a value type of the application, has to have knowledge about Core Data. Usually we’d fare better if we separate Core Data from our own model.

With extensions in Swift (and categories in Objective-C) we have the power to add new behavior to existing types in other locations. Does this help?

Extending a type in a different file hides that detail at first sight – but the extension, when it’s not private, is available in the rest of the code base, too. It just appears as if you put the code in the type definition itself.

Now if Bookmark is included in a “Bookmarking” module you import, an extension can add behavior without mixing Core Data visibly into the model layer. The Bookmarking module will not get altered when you extend one of its types in the client code.

I like organizing Swift code in modules because the boundaries are very strict. You cannot cheat yourself into mixing responsibilities and blurring boundaries that easily.

I’ll be writing a Word Counter Swift module fully East-Oriented

Teaser image

The Word Counter is my biggest software project so far, and it’s growing. To add features, I discovered the use of Swift modules with joy. I can write code for all levels of the new feature in isolation in a new project that compiles fast. Later I plug the resulting project and module into the Word Counter, et voilà: feature finished.

Continue reading …

How to Couple UITableView Cell Identifiers and View Models

Rui Peres proposes to make UITableViewCell view models the topmost model data. Traditionally, Cocoa developers stored something in arrays that corresponded to the indexPath of a cell. In principle, this qualifies as “model” data already, but it’s not yet a view model. In practice, it can even be something different than a view model entirely – and make your view controllers slimmer!

Continue reading …

Separating State from State Changes

Reflecting on a recent change of the Word Counter’s file monitoring module, I think I re-discovered a commonly advised pattern in my code: to separate state from state changes. There’s an object that knows how to handle files based on extension: plain text files’s words are counted differently than Word or Scrivener files. Call it Registry. Previously, this was set up once and didn’t change. Now I wanted to make this configurable so users can add custom plain text extensions. This means changing that object’s state.

Continue reading …

How Closures are a Better Event Handler Protocol Alternative

I don’t like the way I tend to create view controller event handlers. They are almost always just a sink for methods which have nothing in common conceptually but are tied together because of the view’s capabilities. So I began experimenting. Closures can encapsulate changes. This works well with callbacks for Repositories which fetch entities from your data store. Instead of returning them, you can pass them forward:

Continue reading …

iRamDisk May Speed Up Your Xcode Compilation Times

Teaser image

I code on a late 2011 Mac Mini with 8 GB RAM and a 256 GB SSD. This machine is a ton faster than my old MacBook Air was. Compilation still takes time, but it seems that iRamDisk helps a bit.

Lately I wondered if I could cut down the 30s compilation time (3mins with a clean build folder) if I had a Mac Pro, or MacBook Pro, or iMac, or whatever next tier device. Faster cores, more cores, doesn’t matter. But buying a Mac for $3k is out of question at the moment. So I’ve been looking for other tricks.

The only thing that’s faster than a SSD is RAM. That’s when I found the app iRamDisk. It offers an option to move the derived data folder to a virtual disk in RAM. It seems I can reduce the clean build time from 3mins to 2mins with that. Xcode needs about 1.5GB derived data for the Word Counter – at least that’s how big I had to make the RAM disk to not get filled quickly. The overall memory pressure is a bit higher, the Mac is using swap more, but compilation becomes faster at last.

There’s a downside, too: after every reboot the RAM disk is empty, so Xcode has to index the project again and compile fresh at least once a day. Depending on your usage this can be annoying or not be a problem at all.

You can download a trial from the website or buy it for $19.99 on the Mac App Store.

Get Your App Indexed by Google

I did know that universal links help integrating web content and native app scenes: regular web links may show the content in the browser on most devices but magically open the content within your native app when it’s installed. The prime example I knew was IMDB’s movie database, but it obviously works for recipes as well.

Now I read about a Google App Indexing SDK. Before universal links, it tried to achieve the same effect. But what does it do nowadays?

The source code isn’t prominently linked anywhere. I went to the CocoaPods spec and downloaded the source tar file (at the bottom of the spec).

The “source” contains a framework which publishes two classes, GSDAppIndexing and GSDDeepLink. There’s a sample iOS app on GitHub by Google as well.

You use GSDAppIndexing to register your app with its iTunes ID – but the sample application doesn’t do that at all. The docs indicate this is needed to expose content to crawlers, though. The sample app does handle links in AppDelegate:

var currentDeepLink = String()
    
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
    let sanitizedURL = GSDDeepLink.handleDeepLink(url)
    currentDeepLink = sanitizedURL.absoluteString
    return true
}

Instead of routing, it only stores the link for display purposes. There you see what GSDDeepLink is good for: extracting the real deep links from the Google search deep link call.

What’s it good for?

It will show deep links (perhaps more prominently?) when you browse Google on Mobile Safari. In other words, regular visitors with a Mac probably won’t notice any difference.

The following is the expected URL scheme according to the GSDDeepLink.h file, split up into multiple lines for reading convenience:

gsd-<scheme>://<appstore-id>/
    ?google-deep-link=<url-encoded-original-deeplink>
    &google-callback-url=<url-encoded-callback-url>
    &google-min-sdk-version=<minimum-sdk-version>

And an example:

 Annotation:
 ios-app://544007664/vnd.youtube/www.youtube.com/watch?v=aISUYHTkTOU
 
 Original Deeplink:
 vnd.youtube://www.youtube.com/watch?v=aISUYHTkTOU

 Callback URL:
 googleapp://
 
 Final URL:
 gsd-vnd.youtube://544007664/
     ?google-deep-link=vnd.youtube%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DaISUYHTkTOU
     &google-callback-url=googleapp%3A%2F%2F
     &google-min-sdk-version=1.0.0

The following is just totally made up: I assume the GSDDeepLink helper actually sends back some statistics to Google. Otherwise I wouldn’t know what the wrapped URL would be good for at all. (Suggestions welcome.) GSDDeepLink does overlay the status bar for a short while according to the header documentation so users may return to the search results.

I still don’t get the benefit from using Google’s framework in my projects. When users reach my website via Google, the native app is expected to open automatically anyway. So there’s only the formatting of app-related search results left as a benefit as screenshots indicate.