vision pro game in progress

I’m timeboxing the creation of this blog post, so I can continue to work on my game for the apple vision pro. I’ve had the thing for a week now, and in the weeks leading up to the launch date, I began working on a port of a game I’ve worked on previously (but never released) called Puzzle Prison.

I have planned (for quite a while, really) to write a blog post about how and why I never launched Puzzle Prison, but I’ll go into it briefly here. It was a game I developed for originally for Google Cardboard. I actually showed it at an event at GDC one year (2016, maybe?), and at numerous events locally around the Twin Cities. (Various VR & HCI events and meetings, Twin Cities Maker Faire, in the lobby at a TEDx event, and probably other events too.)

The game is fairly simple. It’s a SameGame variant, with the twist that the game is played on four walls, one in each direction. It is a stupidly simple way to bring a 2D grid-based game into the third dimension, and despite having lots of ideas for how to make the game better than what I describe (I implemented a few of them), the simplest game ideas are often the best ones, and the base game idea was probably the best version of it.

Here’s a trailer I put out there at some point:

One reason I never launched the thing was that new platform development kept being more compelling than launching for the current platform. By the time the game was polished enough to release for Google Cardboard, I was doing a lot of “real” (3DoF) VR development, mostly for Vive, and I decided that I thought Google Cardboard was essentially dead, and I would wait to release it when the steam version was finished. Then I had similar thoughts about SteamVR, and wanted to release it for the Oculus Quest. I really should have just launched it on iOS and Android and been done with it.

Anyway, fast forward a bunch of years to this year’s WWDC, and I’m ecstatic to be able to work on a game for Apple’s new headset in Swift! And the APIs look great! I spent some time looking through my various VR game ideas, and nothing really jumped out at me as something as easy to make as Puzzle Prison. The project has another big plus going for it, and that’s the fact that I already have a bunch of awesome audio assets that I’d love to use and include.

Okay, so it’s a week after the headset launched. Two weeks ago, I thought I’d have an app out by now. What’s the holdup?

First thing, the game is playable. I’m tempted to launch a first version as/is, and improve it incrementally. But it’s missing a lot of stuff, and for one thing, I still haven’t implemented those aforementioned audio files.

But there’s another issue I’m working through, and weirdly, it’s related to game design. The original game has what I think are pretty awesome “block breaking” animations. (I’ll get to how this is relevant in a second.) I actually think they may be some of the best animations I’ve ever created in a game. (To be honest, it might be the only animation I’ve ever created that wasn’t directly necessary for a game’s design.) The game without them is totally fine, and playable… except… they take some time. A second or two. And at some point I implemented a feature in the old version of the game where there is a multiplier. If you break more than one group at a time, it increments a multiplier, and the second group is worth more points. But because the game currently has no animation, the scoring isn’t the same as the old game.

There are other effects that I think are more important than the block breaking effect. Namely showing you when and where the game is in danger of ending, as well as an effect for when the game does actually end. Both are not just cosmetic, but have important UX impact. So they may get my attention first, but I’ll get to those block breaking animations eventually.

Introductory Apple Developer Resources

I wrote up a list of Apple (iOS, iPadOS, macOS) developer resources that are not directly from Apple. (Perhaps obviously, if you are wanting to get into developing for Apple’s platforms, developer.apple.com should probably be your first stop. This was written for someone who wanted links to other sites they should know about.)

I figured since I spent a bit of time compiling these, I’d re-post them here.

  • If you still feel like you’re getting a handle on Swift syntax, (or just want to brush up and/or clarify optionals), I highly recommend the Unwrap app. It was instrumental for me when I first started learning Swift.
  • Similarly (on the topic of Swift syntax) https://swiftly.dev/ is a nice “cheat sheet” style site with a lot of topics. (Made by a local dude!) He also made https://iosref.com/ which is another “cheat sheet” for various device-specific info.
  • All Apple developers should at least know there is a book on Swift Language syntax. Importantly, it’s updated for every new version, and you probably don’t want the version that’s currently in beta, so be aware of which one you’re reading. Also, that link is to the overall swift.org documentation, which has a bunch of other semi-interesting stuff listed too.
  • The Swift Package Index should probably be the first place you look for swift packages. Apple is a sponsor.
  • I read iOS Dev Weekly when it hits my inbox every Friday. Might not be as much beginner content there, but it’s definitely the main way I “keep up” on interesting blogs and viewpoints. The intro usually touches on any news I should be aware of as well. (The author is also the maintainer/founder of the Swift Package Index.)

Some blogs that I find myself on regularly (with really nice articles):

  • NSHipster is kind of in-between a blog and a reference site. It used to feel more important than it does to me now, but it’s still a really nice set of articles on some of the tricker topics you might encounter.
  • Hacking With Swift is a source of SO MANY good articles. I have this one on SF Symbols bookmarked, as it’s the definitive guide, IMO.
  • Swift By Sundel has a TON of excellent articles, and this link (the “Discover” tab) feels especially full of “required reading”. The author uses a very nice static site generator written in Swift, called Publish, on Github.

There are also a couple of relevant and local (to the Twin Cities, where I’m based, in Minnesota, USA) developer meetups:

  • Our local Cocoaheads chapter merged with a meetup.com TCiDev group several years back. They have a joint Slack that has a not-zero number of posts per month (but it’s close).
  • SwiftMN is sort of the new-kid on the block. It obviously didn’t exist until Swift came about, and I was a late Swift convert (didn’t start using it until version 4), so I’ve only been to a few meetings. They have a mostly-dead slack also.

On being a self-taught programmer

This post was written this morning in response to a post on dev.to asking about how self-taught programmers got their first jobs. I have told versions of my career path so many times that I think I wrote all of this in about 20 minutes. But I was thinking just now that I’m not sure I’ve written it all out like this before, so I’ll reproduce it here just for posterity.

I’ve been working in tech for well over 25 years. My career path has been long and winding, so I’ll try and give just the highlights here.

I did take a class in Basic in Jr. High school, and an Intro to C in college, but it was while I was in college, as an English major, that I began to teach myself html. This would have been 1996 or so, and I was president of our juggling club. I just wanted to update the webpage for the club, and that’s when I started to learn.

Key take-away for getting a job as a self-taught programmer: When you’re learning, be sure to pick a project or projects that you’re passionate about! It will be so much easier to complete them, and when you inevitably talk about them, that passion will only work in your favor.

Really, I just had small changes I wanted to make to that site. I needed to add myself to the list of “club officers”, and change the meeting times periodically.

Take-away 2: It’s much easier to make small changes to an existing project than to dive in to a large project “from scratch”.

Eventually, I started working on websites for various projects in the English department. One was a grant-funded research thing, and did not have html anywhere in the requirements, but I decided to post our findings / research as a webpage. That led to a very part-time job for another English professor, and that in-turn led to working at the student-run newspaper, writing html for a new “microsite” for the A&E section every week. That was almost certainly my first real job in tech, though it was a student position, and only 10-16 hours per week.

When my financial aid got screwed up at the end of 1999, I just dropped out and it only took me a month or two to land a full-time tech job (it was in the middle of the dot-com bubble). That job was “front-end” work, (html & javascript) and ~2 years later the company merged with another company, and 2004 or so I was the last person remaining from that original. By that time I knew I wanted to do back-end development, or what I considered “real programming”.

Take-away 3: Never stop learning. Try new things when given the opportunity, and you might find you enjoy some things more than others. You can totally shape your own career!

Once I started looking, I had a couple of job offers, but I ended up taking a job with some of my previous co-workers, and the idea was for me to do 50/50 front-end/back-end work. But I never really did much front-end work after that.

Take-away 4: Almost every job I’ve ever gotten has been because I knew someone, or was just in the right place at the right time.

Around 2007 I decided I could teach myself flash, just long enough to make my first video game. (I followed a tutorial on how to make Tetris, then modified it to have very different rules.) Around that time I started attending meetings of our local Twin Cities chapter of the IGDA, which I found very inspiring. I did my first public speaking, talking about my Flash game, and it seemed pretty well received!

Take-away 5: If you can, working on side projects is almost always rewarding. It’s especially important to get them to the point you’re not afraid to show them off, and put them in your portfolio or resume. (I do think portfolios are more important for folks who are self-taught than for folks with comp/sci degrees.)

Toward the end of 2008 I decided my next game would be for the iPhone. I spent a lot of nights and weekends, and I think I really leveled-up my programming working in Xcode and Objective-C. (I fell in love with strongly typed languages.) About 3 months later I released my first iPhone app in the store.

Around 2011 I’d been attending lots of meetups related to App development, and I’d worked on several projects, both personal and for my employer. (But it was still mostly web-dev at my day job, even though my passion was clearly for mobile.) I gave several talks at a group called Mobile Twin Cities, and the founder of that group had a mobile consultancy, and he recruited me.

Take-away 6: Find user-groups in your area that are relevant to the work you want to do. Attend them and (ideally!) find a way to give a talk. (Or at least address the group for a few minutes. Most groups have time for announcements.) Putting yourself out there, especially in a way that shows off your skills/abilities, can be crucial to landing any job in tech.

I think I was only at that company for 6 months before another merger was announced, and a year later, I found myself no longer writing mobile apps, but doing macOS desktop application development instead. I lined up a contract gig, (fortunately a very flexible one), and gave my notice.

They convinced me to stay a whole month before leaving, but in 2012, I began working freelance/contract, and I’ve been my own small consultancy ever since. I’ve even managed to work on a bunch of games! (Though my passion is definitely still mobile, I’ve done some VR work, and I’m currently very excited to work on some projects in visionOS.)

I hope someone finds this helpful.

Apple Vision Pro – the wait is over; the wait begins

I’ve been waiting patiently for Apple to reveal their headset for at least 5 years now, and as of WWDC 2023, that wait is finally over. A couple of weeks later (last Tuesday), the developer tools dropped, and I finally got a chance to start working with the frameworks and applications that Apple has created for making content on their new headset.

I’ll be eagerly exploring these frameworks and playing with this tech at least until the headset is covering my eyeballs, and (hopefully) for years after. There’s literally so much here that they devoted over 40 (admittedly short) WWDC talks to the topics, (with some overlap, sure, but not as much as you’d think). I have done a fair bit of VR development in the past, and while it’s been a few years, (and I’m sure there’s been some improvement in that time), to me, Apple’s APIs seem like the most flushed-out and easy-to-use way to develop 3D applications that I have ever seen. The only downside I can imagine is the vast amount of new frameworks to learn. There are seemingly a lot of ways to approach the same problem, or similar problems anyway, and I could imagine that being daunting for a lot of people. Fortunately, the documentation is quite good.

I imagine I’ll be writing about this topic a bunch in the next few months, and for my first post on the topic I’m going to just document some of my findings about the coordinate system in visionOS. I’ll jump right in.

position coordinates in immersive space

So I’ve been doing some programmatic drawing experiments on visionOS, and as anyone who has ever drawn things on a screen knows, one of the first things you need to know is:

Where is the center of your drawing area, or x: 0, y: 0, z: 0?

In short, when you open an Immersive Space in visionOS, 0,0,0 is positioned directly beneath you.

While the immersive space remains open – even while you move around within the space – 0,0,0 doesn’t move. But if you close the immersive space, and re-open it, 0,0,0 will have moved to a new location and rotation, again directly beneath your feet, and rotated to face the same way you are facing.

So, because the coordinate space will always appear in the same orientation as you, the following are always true (when you first open the space):

  • -x is to your left, and +x is to your right
  • -y is down, while +y is up
  • -z is forward, and +z is backward (behind you)
    I’m not sure I love that last z-direction decision, but it’s how it works.

Note that animating a transform is as easy as this code snippet:

.gesture(TapGesture().targetedToAnyEntity().onEnded { value in
    var transform = value.entity.transform
    transform.translation += SIMD3(0.1, 0, -0.1)
    value.entity.move(
        to: transform,
        relativeTo: nil,
        duration: 3,
        timingFunction: .easeInOut
    )
})

That example is from the WWDC video Develop your first immersive app.

I have a long list of things to explore next, but at some point in the near future I’ll be exploring drawing and transforms and coordinate spaces in what apple is calling “volumes”. (Volumes are 3D windows, or bounded boxes, essentially.)

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.

Blither for iOS

Last week I launched an app for my board game Blither. I’ve written about Blither on this blog twice previously, the first time describing Blither’s rules and a bit about how and why it was created, and the second time talking more about some basic play strategy. I was particularly proud of Blither as a game when I first designed it, and I am still pretty happy with it.

After launching the app, I spent a bunch of last week improving it in a lot of ways, and I recorded a video introducing the app and showcasing some of those changes on Sunday:

As you can see if you watch the video, I was (and still am) especially excited about the “high score mode” (which I’d only finished coding-up that day).

For now, the app is just $0.99 (USD). I’ve got a long TODO list in the project’s README, but I’ve already said semi-publicly that I’d like to increase the price when I hit certain milestones:

  • I’ll add $1 to the price when I add an actual interactive tutorial (that’s probably next up)
  • another $1 if I can get the AI up to at least “giving me a challenge” level
  • and +$2 if or when I add asynchronous multiplayer (almost certainly via GameCenter again)

I’d also like to add some leaderboards for that “high score mode” I mentioned. We’ll see.

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!

why I prefer not to teach kids visual scripting

I’m actually pretty adamantly biased against visual programming (sometimes referred to as block-based coding, or visual scripting). I’ll elaborate.

First, it’s important that you understand visual programming to be generally more limited in scope and capability than most (though certainly not all) text-based computer programming environments. Most block-based coding frameworks are written “on top of” some other coding environment, and will have only as many features as the programmers of them have bothered to (or had a budget to) implement as a subset of those features and capabilities of the original environment. But it’s also worth noting that the original APIs they are coding on top of will probably be changing as fast (or likely faster) than they have time to implement in the block-based equivalent. So even if the desire is for 1-to-1 feature parity, they will likely always be a subset. (Worth noting that as far as I know, no block-based coding environment has been written in a block based language, they are all coded in some other text-based language environment.)

So why is it bad that it’s limited? This is just for teaching right? Well, my argument is mainly that I believe we tend to prefer to do things the way we first learn to do them**. It seems like most proponents of block-based coding are in education, but I don’t think that the folks teaching it, while they are obviously well-intentioned, realize that there are a limited number of practical applications of block-based coding.

Obviously context matters here. If you are teaching a specific tool that exists for a specific purpose to someone who only wants to be able to do that thing, then maybe that’s fine. I’m mostly opposed to teaching kids (or more even adults) more generally the concepts of coding by teaching them those concepts using visual-coding or block-based coding.

I think it goes like this: if you are presented with the choice of teaching a kid to drag some cool looking blocks around a screen versus getting them to type some (possibly esoteric) syntax into a text editor, then drag and drop seems like the obvious choice! And I can even see an argument that teaching coding concepts, it might seem like decoupling them from a programming-language specific syntax seems like a good idea… but I think most people, when moving beyond learning the initial concepts, are going to prefer to do it the way they first learned it. And that’s where the problem comes in! if the way they first learned to code was with blocks, they’re going to be used to (and possibly prefer!) a fairly limited way of coding.

Code is text. Text is code. “visual coding” is putting a graphic design on top of text. You might argue that all programming languages are built on top of other programming languages, and that’s true, and I’m certainly not arguing everyone should learn assembly before they learn C. But I will argue that you should learn Python before you learn a VPL.

As an aside, I struggled to find a good metaphor for this article. The closest I got was this: It’s sort of like communicating with Emoji. You can definitely get some meanings across, but if you are going to be nuanced about it, or have something very specific you need to communicate, it’s definitely not going to be good enough. But if you never learned to spell, and only learned emoji, you would be at a serious communication disadvantage. This metaphor breaks down pretty quickly though.

**BTW, if it turns out you have (or know about) evidence that I am wrong about this basic premise, I’d love to hear about it. It fits with my understanding of human behavior, but I’m certainly no expert on human psychology!

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.

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.