Nick Harris

Archive for June 2016

Introducing Super Euchre 2.0 and Solitary Solitaire 1.0

leave a comment »

If you’ve been following along with my blog about my re-write of Euchre, my Solitaire challenge and me learning Swift and wondered if I’d ever release them to the App Store, well the wait is over!
(then some thoughts on the last couple of months)

Super Euchre 2.0

Icon 180

https://itunes.apple.com/us/app/super-euchre!/id697411524?ls=1&mt=8

– Brand New Layout and Card Faces
– New Game Replay
– Stats
– iPad Landscape and Multitasking Support
– Stats synchronization between devices

Solitary Solitaire 1.0

Icon 180

https://itunes.apple.com/us/app/solitary-solitaire/id1123243052?ls=1&mt=8

– Single or three card deal
– Auto play a winning hand
– Best time, score and moves
– iCloud syncing of games
– iCloud syncing of best time, score and moves
– Landscape support for iPhone 4S through iPad Pro
– Multitasking support on iPad

Swift

Both apps a written completely in Swift 2.2 from my standpoint. I get that the Objective-C runtime powers them but there is not one line of Objective-C in my repositories. I’ve been writing Objective-C for about half my career at this point (7 out of 15 years) and I still like the language. Its odd and quirky but I can make the devices I love do things with it so its cool by me.

Swift though… I love Swift!

Super Euchre in particular was much easier to code this time around. Higher level functions like sets, map and filter made writing the player logic much easier. I realize now that I could have accomplished the same type of approaches in ObjC using more NSPredicates but in actuality my past code was littered with tons of for loops. The Swift code to me is much easier to read and understand.

After higher level functions, my second favorite aspect of the switch to Swift is how much more I pay attention to mutability. For the player logic I decided to use NSOperations to compute some type of decision. In the past I’d have that code in one monolithic class. Using NSOperations allowed me to concentrate just on one small piece of logic making it easily testable. As far as mutability, all of my operations and even internal functions never mutate any of their input parameters. All operations have a operationResult parameter that holds the computation. No function uses the inout keyword. Even functions that do something as simple as sorting use a return value and @warn_unsed_result to remind myself that none of my functions ever mutate. I really like this approach and plan on using it in the future.

Auto Layout / Adaptive Layout

I haven’t used Xcode 8 yet but what I saw in the Platforms State of the Union at WWDC I think would have made both these games SOOOO much easier to create. If you’ve ever created landscape layouts with size classes you probably know what I mean. Interface Builder in Xcode 7 means working in a canvas that doesn’t have the same dimensions as any device you’re creating it for. Xcode 8 looks like a much better experience.

Multitasking was incredibly simple for both since I was already supporting devices from 4S up to the iPad Pro. Getting the layout right for the other devices meant multitasking was already done. I think users of such stupid time wasting card games will appreciate it!

One thing I did do different with auto layout in both of these games is to use placeholder views in the storyboards then adding all the actual views on viewWillAppear. The placeholder views give me the correct frame when the game starts (and also after rotation or switching multitasking size). What it saved me – particularly for Solitaire – was having every card in play represented on the storyboard. It made all the animations easier. Because the views that I add on viewWillAppear don’t have any auto layout constraints, I can animate their frames instead of updating their constraints (via tons of IBOutlets). I’m not sure that I’d do this very often in the future but this approach worked really well for these games.

iCloud Key / Value Storage

Both games use NSCoding and NSUbiquitousKeyValueStore to sync not only stats and best scores across devices but also unfinished games. I’m still not sold on this. It works well enough that I don’t think most people will notice how long the lag between synchronizing on one device and getting the update on another device can really be. I’m guessing in real world use, the 1 to 5 minutes won’t be noticed. We’ll see. I have a feeling this will be the biggest source of complaints and bad reviews.

App Store Preview Videos

When I first started figuring out how to do these I was so close to throwing in the towel and skipping them. I’m glad I didn’t. Once I figured out how to have an easily re-playable sequence in both games and liked what was being shown, recording and editing in iMovie for 5 different devices was pretty quick (iPhone 5, iPhone 6, iPhone 6S+, iPad, iPad Pro).

I have much more appreciation for app developers who have a preview video. I also think you get a better idea of how the app feels with a video rather then just screenshots. Will they drive more downloads? I don’t know. But now I know how to make them so that’s another skill in the toolset.

Test Flight

Loved it. Would use it again. I should note that I haven’t tried any of the newer beta distribution platforms, but Test Flight did everything I needed it to do with very little friction.

AdMob

Monetizing an app with advertising is always a little controversial. I wrote these two games to teach myself Swift, get more experience with auto layout and multitasking as well as learning the latest version of iTunes Connect which I hadn’t touched in 2.5 years. I see them more as my playground to learn and use the latest and greatest Apple technology. I don’t think I’d learn as much if I didn’t release them. Having real users is critical in learning and understanding the entire Apple ecosystem. But I want my expectations from users to be realistic. I get to learn new fun things and they get to play them at the cost of a few ads. If I want to completely redesign an app to learn something new (which I did with Super Euchre) I don’t feel the same obligation to users that I would if I were charging them. That may seem cynical and an altruistic approach of completely free apps may be more palatable for a user but I did spend 4 months working on these games. Realistically I expect to make about $100/month pre-tax on these games. I’m already practically giving them away.

I am curious though if banner ads really do underperform against interstitial ads. Euchre has a banner add while Solitaire has an interstitial ad when starting a new game. It should be interesting to see which wins.

Overall

I hope people enjoy these games. These last few months have been a lot of fun creating them, getting them to testers and polishing them off. I’ve learned a ton!

Then WWDC happened.

Now to update both code bases to Swift 3.0…

Written by Nick Harris

June 23, 2016 at 6:59 am

Posted in Uncategorized

Protocol Oriented Programming

leave a comment »

The term “Protocol Oriented Programming” has been thrown around a ton over the last year. If you’re wondering what it means, here’s an example that I dealt with tonight while working on Euchre…

Problem

Over the weekend I implemented a way to save multiple in progress games and have iCould key/value storage sync them across devices. The initial implementation was pretty dumb and saved any game in progress. This lead to a long list of saved games just in my testing. That’s not a great user experience. The user should make the decision to save their current game or delete it.

In the app the user can start a new game from the regular Game View or they can elect to resume a game which shows the Saved Games View:

Screen Shot 2016 06 06 at 11 03 37 PM     Screen Shot 2016 06 06 at 11 03 52 PM

Both of the views need to be able to prompt the user to save their current game. They both also have different actions once the user makes their decision.

Protocol Oriented Programming Solution

The best way to solve this was to first create a protocol named SaveGameProtocol that has the current GameController that I want to archive:

protocol SaveGameProtocol {

    var gameController: GameController? { get set }
}

 

Next was to add an extension to that protocol that does the save / delete prompting and handles the users decision before invoking a completion handler. This makes the extension very generic. It does its save / delete job but leaves the rest up to whatever SaveGameProtocol adhering UIViewController that wants to call it.

extension SaveGameProtocol where Self: UIViewController {

    func promptUserSaveCurrentGame(completionAction:(()->())) {

        let alertController = UIAlertController(title: NSLocalizedString("save_game_alert_title", tableName: "GamePlay", comment: ""), message: nil, preferredStyle: .Alert)

        let saveGameAction = UIAlertAction(title: NSLocalizedString("save_game_button", tableName: "GamePlay", comment: ""), style: .Default) {
            action in

            if let currentGameController = self.gameController {
                SavedGamesManager.sharedInstance.saveGame(currentGameController)
            }

            completionAction()
        }
        alertController.addAction(saveGameAction)

        let deleteGameAction = UIAlertAction(title: NSLocalizedString("delete_game_button", tableName: "GamePlay", comment: ""), style: .Destructive) {
            action in

            if let currentGameController = self.gameController {
                SavedGamesManager.sharedInstance.deleteGame(currentGameController)
            }

            completionAction()
        }
        alertController.addAction(deleteGameAction)

        presentViewController(alertController, animated: true, completion: nil)
    }
}

 

There is a trick here though. In order to present the UIAlertController using presentViewController we need to make sure the caller is a UIViewController subclass. That can be enforced by using a where clause on the extension:

extension SaveGameProtocol where Self: UIViewController

 

The last step was to set both my views to conform to the SaveGameProtocol then call the extension with whatever code each needs to continue.

Screen Shot 2016 06 06 at 11 20 34 PM     Screen Shot 2016 06 06 at 11 20 20 PM

And that’s it! Shared save game prompting code for any UIViewControllers that needs it!

Swifty!

Hat tip back to Natasha the Robot  for the pattern.

Written by Nick Harris

June 7, 2016 at 5:41 am

Posted in Uncategorized