How Blither uses the coordinator pattern and SwiftUI together

I never have enough time to work on the games that I make. So when I am working on them, I want to stay focused on the game screen, and spend as little time as possible writing the other boring (but still necessary!) screens for the App. Apple’s SwiftUI framework is very easy to use, and if you don’t much care about making things pixel-perfect, it can sure save a lot of time.

I am not yet convinced that SwiftUI is all that great at navigation, however. I feel like I only just got used to coordinators in UIKit (admittedly many years ago now), and maybe I’m still in the honeymoon stage with them or something.

So for my latest game, Blither, and somewhat by extension this open source Hexagon Grid Generator that I released, I’m using SwiftUI for all the straightforward UI, SpriteKit for the “interesting” views (game and grid), and UIKit mostly just for its UIViewControllers.

In Blither, I have a single UINavigationViewController, and a class named AppCoordinator that manages the navigation stack. It looks like this:

public final class AppCoordinator {

    public enum Route: Int {
        case about
        case appIcon
        case back
        case game
        case mainMenu
        case newGameConfig
        case options
        case rules
        case stats
    }

    public let navigationController: UINavigationController = {
        let controller = UINavigationController()
        return controller
    }()

    public func navigate(to route: Route) {
        if let presented = navigationController.presentedViewController {
            presented.dismiss(animated: true)
        }
        switch route {
        case .about:
            let viewController = AboutViewController()
            navigationController.pushViewController(viewController, animated: true)
        case .appIcon:
            let viewController = AppIconSceneViewController()
            navigationController.pushViewController(viewController, animated: true)
        case .back:
            navigationController.popViewController(animated: true)
        case .game:
            if let topVC = navigationController.topViewController, topVC is GameViewController {
                // already showing the GameViewController, so pop first
                navigationController.popViewController(animated: true)
            }
            let gameViewController = GameViewController(coordinator: self)
            navigationController.pushViewController(gameViewController, animated: true)
        case .mainMenu:
            if let topVC = navigationController.topViewController, topVC is MenuViewController {
                return // already showing the MenuViewController
            }
            let menuViewController = MenuViewController(coordinator: self)
            navigationController.pushViewController(menuViewController, animated: true)
        case .newGameConfig:
            let configVC = PlayerConfigurationViewController(coordinator: self)
            navigationController.present(configVC, animated: true)
        case .options:
            let viewController = OptionsViewController(coordinator: self)
            navigationController.pushViewController(viewController, animated: true)
        case .rules:
            let rulesViewController = RulesViewController(coordinator: self)
            navigationController.pushViewController(rulesViewController, animated: true)
        case .stats:
            let viewController = StatsViewController(coordinator: self)
            navigationController.pushViewController(viewController, animated: true)
        }
    }
}

That may look like a lot, but if you look closely, almost every switch case is the same. The AppCoordinator instance is created in the app delegate’s standard didFinishLaunching function:

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    /// The root coordinator for the app.
    var appCoordinator: AppCoordinator?

    /// The main window
    var window: UIWindow?

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {

        let window = UIWindow(frame: UIScreen.main.bounds)

        let appCoordinator = AppCoordinator()
        self.appCoordinator = appCoordinator

        window.rootViewController = appCoordinator.navigationController
        window.makeKeyAndVisible()
        self.window = window

        Blither.setup()

        appCoordinator.navigate(to: .mainMenu)

        return true
    }
}

All of those View Controllers getting created in the AppCoordinator are UIHostingController subclasses, and look almost exactly like this one for the main menu:

public final class MenuViewController: UIHostingController<MenuView> {

    private weak var coordinator: AppCoordinator?

    init(coordinator: AppCoordinator? = nil) {
        self.coordinator = coordinator
        let menuView = MenuView(coordinator: coordinator)
        super.init(rootView: menuView)
    }

    @MainActor required dynamic init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

If you’ve worked with SwiftUI and UIKit together before, you’ll recognize the UIHostingController, but even if you haven’t, all you really need to know is that MenuView is a standard SwiftUI View, meaning it’s dramatically fewer lines of code to add something like a button. And because it also holds a reference to the AppCoordinator, the definition for a button can look like this one:

                Button("Read the Rules", action: {
                    coordinator?.navigate(to: .rules)
                })

When that’s tapped, the coordinator pushes the RulesViewController onto the stack.

If I wanted, I could get rid of the coordinator reference, and do something like this:

                Button("Read the Rules", action: {
                    (UIApplication.shared.delegate as? AppDelegate)?
                        .appCoordinator?.navigate(to: .rules)
                })

…but I don’t like how that looks quite as much, and it also closes the door on dependency injection.

Hopefully you can appreciate how simple this all is! I’ve been pretty happy with how easy I found it to create new screens using this framework. Let me know in the comments or over on mastadon if you have done something similar, as I’d love to hear about similar approaches.

Xcode tips and keyboard shortcuts

I love working in Xcode. It was my first “real” IDE experience, and while I still use vim pretty regularly it’s generally not for editing code (anymore). These days, whenever I’m not working in Xcode (lately it’s almost always Visual Studio on Unity projects), I’m wishing I was.

I read iOS Dev Weekly (https://iosdevweekly.com/) most weeks, and it was via that lovely resource that I discovered this great GitHub page full of Xcode-Tips (https://xcode-tips.github.io/). I already helped include one tip there (about enabling spell-check), and this post is inspired by one of the tips I found there in particular, about using `cmd-shift-j`. 

Xcode is a 3 panel layout. The middle panel where you actually edit code can be split up in a number of ways, (tabs within tabs? c’mon), but I won’t go into that in this post.

The left panel is called the “Navigator”. It has tabs across the top and defaults to the first tab, or “Project Navigator”, showing all the files in your project hierarchy. 

  • Filesystem tip/aside: When I first started using Xcode I was surprised to learn that files presented here are not necessarily 1-to-1 with the files on the filesystem. On one of my current projects, we are using the awesome open source XcodeGen (https://github.com/yonaskolb/XcodeGen) to generate the project from files on the filesystem. It’s actually called from a script that we run from a git checkout-hook, so we almost never have to think about it. This was a new-to-me workflow, but has a lot of benefits, including keeping the project files consistent with the filesystem!

Keyboard shortcuts relevant to the navigator:

  • Hide (or show) the whole Navigator pane with `cmd-0`. (That’s a zero.)
  • Jump to any of the tabs in the navigator with `cmd-<number>` where number is the index of the tab. So `cmd-1` opens the Project Navigator. This works even when the Navigator is hidden!
  • Best of all, the aforementioned `cmd-shift-j` will open the Project Navigator and select the file you are currently editing. You can then use the up or down arrows to browse different files, and `cmd-j` and then `enter` to return to the code editor.

The panel on the right side of Xcode is the Inspector. It too has tabs, and what’s great is that the keyboard shortcuts are very similar to the ones for the Navigator, but with the addition of alt:

  • Show/Hide the Inspector with `cmd-alt-0`.
  • You can also jump to one of the tabs with `cmd-alt-<number>`, again, where number is the index of the tab. What’s interesting here is that there are a different number of tabs here if you are editing an interface builder file. (I don’t think I’ve ever used these shortcuts.)

In general, I am far more likely to want to hide the Inspector pane than the Navigator pane, so it’s kind of a shame the shortcuts to show/hide them aren’t reversed (not to mention the fact that cmd-alt is a difficult combination on my Moonlander keyboard, but of course I could fix that).

I wrote this up in part so I can create another PR and reference myself as the source for a tip about showing and hiding these panes, but this post was also inspired by sharing with another member of my team that I do the majority of my development on a MacBook, without external monitor. <insert scream emoji> One of the aspects that makes that experience tolerable are all these keyboard shortcuts that let you maximize the space you’re using to edit code quickly and easily.

I hope you learned something from this, but if you didn’t, go check out that Xcode-Tips site, because you’re sure to learn something there!

iOS Updates and version numbers

First of all, the update to Catchup I mentioned a while back is finally live in the app store today! This got hung up a bit because Nick wanted me to make the new catchup rule the default. I told him I would definitely do this if he would handle translations of the rules update. (But of course wrangling a bunch of translators is much more difficult than the few lines of C++ needed to make the rule change itself!) So as of this writing, the rules change is still optional (and off by default). If and/or when we get some translated rules, I’ll probably push out another update to flip the default.

I’m also working on updates to some of my other apps. Unfortunately, it’s not really a straight-forward process, and there are some that will still probably not get an update at all. (Action Chess, for instance, just needs to be entirely re-written, which I’ve pretty much decided I’ll just do in Unity rather than go for iOS native.)

But in all the apps I’ve done so far, one thing I’ve had to do is change the code that shows the version number. I thought I’d write a mini-tutorial because this is kinda dumb. In pretty much all my apps, I previously had this block of code somewhere (usually in an AboutViewController class’s ViewDidLoad or ViewWillAppear method):

[self.versionLabel setText:[NSString stringWithFormat:@"v%@", [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]]];

…but now I’ve changed it to the following:

[self.versionLabel setText:[NSString stringWithFormat:@"v%@.b%@", [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"], [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]]];

This results in a version number that looks something like v1.4.b2.

(It’s worth noting that I highly recommend putting a user-facing build number in your all your apps somewhere. This is super important for getting bug reports and feedback. The technique above allows your code to update that user-facing number without having to include it in your code directly.)

In case it’s not clear, self.versionLabel is a UILabel instance, either initialized in code elsewhere, or (more likely) in a Xib or StoryBoard.

Anyway, Apple put out a technical note about version numbers and build numbers back in 2015, but somehow I missed it. Now I’m not 100% sure about this (possible it’s just that I was always confused about this), but my theory is that, at some point (maybe around 2015), the CFBundleVersion key changed functionality, from the version number to build number, and the CFBundleShortVersionString was introduced as the new version number. (This is really difficult to google for, I tried, so if anyone has a more accurate historical rundown, I’d be interested in hearing it.) Anyway, both string are required, but the build number is specific to the version number. (I.E. both have to increment for actual releases, but if you bump the version, you can reset build number back to 0 or 1, or whatever.)

These values are changed in Xcode, in the general project settings. Worth noting that the version number is shown to the user in the app store, but I don’t think build number is exposed anywhere (that I’ve seen). I usually try to follow semantic versioning, with the actual version number containing the first two dots (major and minor version changes), and more or less use the build number as the third “patch” number.

I guess the thing I find the weirdest about these bundle keys is that neither one is named “build”. And I would expect the build number to be the shorter one, not the version number. But maybe that’s just me! Hope this helps someone.

Get ’em while you can!

Last week, as part of their initiative to clean up the app store, Apple marked two of my oldest apps as needing updates or they’ll be removed from the store (in 30 days). Since I don’t really have time to update them right now, I’m changed their pricing to free so everyone has a chance to download them before they’re removed. When I do get around to doing updates, I’ll definitely put them back back in the store as paid, so get ’em while they’re free!

The affected games were ActionChess and Oppo-Citrus.

These are games that I’m really proud to have made, so if you haven’t played ’em, please do go check them out. (And let me know what you think!) Enjoy!

Protocols all the way down

As a programmer, one of the things I like to argue against is the concept of “magic code”, code that works because of some unseen bit of code elsewhere. In iOS, the principal is exemplified by “magic” methods you can include in various subclasses that do rather important things. Want to handle touches in your UIView? Just implement the method touchesBegan:withEvent:, touchesMoved:withEvent:, touchesEnded:withEvent:, and touchesCanceled:withEvent:, and you’re good to go. Want to set up your UIViewController‘s visual layout? Make sure you do so in the layoutSubviews method.

But how do you know about all these magic methods? This is definitely one of the questions that I found the most difficult when I first began iOS development. Learning about all this magic is basically the same thing as learning iOS development. Knowing Apple’s APIs is how you develop iOS apps. Knowing their quirks is how you get to be an expert.

But if you’re just starting out, it’s important to know that most of these magic methods are (generally, not always, but generally) defined in a protocol. When an object conforms to a protocol, it basically says that it (or one of its subclasses) will implement some set of methods. Want to know what protocols UIViewController conforms to? In Objective-C, you would simply open up its header and check it out. (Of course, a protocol might be defined even further up the chain, in one of the headers for a class the view controller inherits from.)

But how do you figure out what protocols a class conforms to in Swift? As near as I can tell, the only way is to open up Apple’s documentation. This seems like it would not be enough, since you might be working with a non-apple framework, or worse… it is possible (gasp) for Apple’s documentation to be spotty or outright incorrect. (I’ve done a few google searches, and read about 20 tutorials and blog posts, and I still don’t know how to figure this out from code alone, so I’m really asking this question. I’ve also started a stack overflow question on the topic.)

I don’t want this to be a “I think Objective-C is superior to Swift” post, but I do think there are legitimate reasons for header files, and this is one of them. Once you get beyond a certain level of iOS proficiency, poking around in those header files is akin to using the “view source” as an intermediate web developer. It’s one of the ways you learn how other people approach a problem.

Tetris-like games for iOS

I’m backing up my iPhone in prep for a new device, and one of the things I did was spend ten minutes taking screenshots of every folder, just in case I need to restore things “manually” later. (Actually, I may decide to start “from scratch” on this new device, and I’ll use these images as reference if I need them.)

Anyway, nobody probably cares about my home screen, but I thought these screenshots of my “TetrisLike” folder were pretty cool. Enjoy!

IMG_3095IMG_3096IMG_3097IMG_3098IMG_3099

Watching videos — WWDC, Swift, POP, and grid-based games

This week has been all about learning, and specifically about watching videos to learn. Mostly because this week is Apple’s big WWDC conference. The list of developer-specific stuff they’ve announced this week is perhaps slightly larger than usual (including a new programming language called Swift — more on that later), and I have been watching a ton of talks pouring out of San Francisco in video form. (Special thanks to Apple for releasing them so expediently!)

Normally I am fairly un-enthusiastic about watching videos to learn. I’m much more of a do-er than a view-er. I’ve got to be working with the code in order to absorb a new programming language, so the Swift videos in particular have been somewhat frustrating. I did spend most of Tuesday with the OSX 10.10 and Xcode 6 betas, and Swift specifically, but after spending a lot of unnecessary time tripping over syntax, grammar, (and copious crashes) decided to go back to videos (and getting some actual work done).

My impressions of Swift are pretty mixed. On one hand, I love that they’re trying to make a language that is simultaneously more accessible and also less prone to bugs. That is as fantastic and commendable as it is self-serving. On the other hand, I’m not yet convinced it’s going to be an instant switch for me. I had lots of little niggling problems with the syntax. For example, I’m not sure the benefit of declaring strongly typed variables using generic keywords (var and let). In the c-based syntax languages I know and love, you declare the variable with the type. So in swift:

var view = UIView()

vs Objective-C:

UIView *view = [UIView new];

Now, the first example isn’t ambiguous or anything, but how about this one:

var views = UIView[]()

This is how you declare an array of UIView objects. I do like that it will always (and can ONLY) be an array filled with UIView objects, but I do think it’d be incredibly easy to miss the brackets. Overall though, most of the problems I had weren’t with the language itself, but with the tools, which I think are just not ready yet. I mostly agree with Austin Zheng when he says (from the comments of his 2048 port to Swift): “Xcode is as unstable as always. The background compiler/code analyzer kept on crashing and restarting itself. Xcode was functional enough to allow the project to be brought to some state of completion. The debugger is horribly broken though.”

All my video learning this week actually started on Monday (while waiting for the WWDC keynote to start) with watching Facebook’s video on building the paper app. This is also the one in which they announced their open-source animation framework pop. (And was recommended to me to learn about why it might be useful.) At an hour and a half, it’s a long video, but worth watching not just for the pop stuff (which is absolutely interesting, particularly if you already use Core Animation in your code), but for a multitude of other insights into how Facebook writes it’s apps. (There is some seriously interesting iOS engineering going on over there, something I did not expect given their history and track record, particularly in the quality department.)

Finally, yesterday (after fully maxing out on more WWDC videos), I randomly stumbled onto a talk about SpriteKit and grid-based games. The first half of the talk, by Scott Kim goes into great detail about several different kinds of grid-based puzzle games (on iOS specifically). He more or less breaks the talk into categories organized by gesture, which I think is an arbitrary distinction. (I’ve talked before about how I think the best games provide both tap and drag control schemes that are not incompatible.) Otherwise I think he does a really great job with the topic, and while it’s nowhere near comprehensive, it’s a very nice introduction / survey of the topic. This is very close to a talk that I’ve been thinking seriously about writing. (I first mentioned this idea in a previous blog post.) But since I haven’t (yet) written my taxonomy of grid-based games, Kim’s talk is, at the moment, much better than mine.