indie iOS developer toolkit

Where do I start?

We’re frequently asked by fledgling developers, “where do I start?” and “what do I need?”. It’s a tough question to answer given everyone has different learning preference. That being said, we have come to realize that we send a pretty standard response. Whether our clients are interested in taking the plunge, our friends are curious about the inner workings of mobile software design, or the casual Reddit user asks for insight, we’ve found ourselves giving a similar response.

Well, okay then. What’s that response?

We’ll cut right to the chase. Our go-to list covers our favorite resources for the new indie (and cash-strapped) developer. We’ve personally used these tools and have grown so fond of them, that we still use a lot of them (in lieu of commercial grade software).

Our List

  • Learning Swift (or any other language, for that matter)iOS 13 & Swift 5 – The Complete iOS App Development Bootcamp by App Brewery on Udemy. We speak about this in our write-up on the perfect time to learn a new skill.
  • GitHub – This one is obvious, but we’d be remiss if we didn’t mention it. Get source control! While Xcode has a local repository, remote source control is imperative.
  • 2D graphics – We really like pixel art. It’s quick, easy to pick-up, and lightweight. We’d recommend starting your 2D graphics journey with one of the numerous apps on the App Store of your choice. We’ve had good experience with Pixel Studio.
  • 3D graphics – Just as we recommended pixel art for beginning graphics design, we’d recommend voxel art for 3D resources. Check out Magica Voxel to get started!
  • Text editors(-ish) – Thought we’d mention that we’re big fans of Atom for editing most text files (excluding Swift files). We also leverage PLIST Editor for working with property lists.
  • App Icon Generator – A nifty tool to convert your app icon to the required sizes.
  • GarageBand – The stock Apple app is perfect for creating your own loops and one-shot sounds. While it takes some time to master, you’ll be amazed by what you can generate quickly.
  • Splice.com – In the event you’re not interested in learning a new (virtual) instrument. Splice has you covered. The 100% royalty-free for commercial use audio is great for DJs and app developers alike.

That’s not enough!

While having the right toolset certainly makes the job easier. You can’t accomplish much without a community. Be sure to find other like-minded folks who share your passion for development and design. Reddit is perfect for this. Indie Hackers is great too.

Similarly, marketing is everything! Don’t neglect graphic design. While advertising is out of scope for this article (stay tuned!), it can be incredibly helpful in sparking interest and getting your brand out there.

Finally, remember to pay it forward. Once you get going, you’ll pick it up quickly and will then share in the efforts to educate the newcomers.

What’re your favorite tools? We’re always eager to try out new things.

importance of documentation

Image by Ylanite Koppens from Pixabay

“Comment” on the journey

When was the last time you stopped to give pause and to reflect on where you’ve been and how you’ve arrived at the “now”? Yes, discipline in providing detailed code commentary and in crafting descriptive git commits is critical to the success of any coding project, however, that’s not what we’re getting at here.

While certainly analogous to project documentation, what we’re discussing here is keeping a written log of your journey. Whether you’re an aspiring business owner, established entrepreneur, or independent free lancer, you owe it to yourself to take inventory of your progress. Lessons learned are best recognized in written word. The power of writing has long been tied to an improvement in critical thinking skills.

Pick up a pen (or keyboard)

Where are you right now? How did you get here? What would you do differently or do the same? Answer tough, open-ended questions. Write until you’re exhausted – don’t worry about punctuation, spelling, or grammar. Focus instead on writing in a stream of consciousness fashion until you’ve expended all thoughts.

Start small. Reflect on the past day or the past week. Describe deeply how you’re feeling in the moment. This is real history. Recording the progress you’ve made with regard to assessing your feelings of doubt, motivation, failure, and success is a key, leading indicator of future performance.

Pick up a pen or sit down at a keyboard. Start writing for 15 minutes. Do this daily. Build the habit of reflecting.

Write for you

Write for yourself. This doesn’t have to be shared. Give an honest assessment of your progress toward your goals. To be honest, you don’t even need to reread what you’ve written. We’d argue that the process is more important than the content.

That being said, sharing your insights is invaluable. Whether you’re sharing them with friends or writing to the vastness of the web, your unique insights and experiences are bound to resonate with an audience. Think of how differently our professional experiences would be if more wrote about their often-deemed “mundane” jobs (improperly categorized as such). Sharing personal reflections of daily learnings and observations in the workplace is invaluable to students (and we’re all students regardless of life stage).

Questions to ponder

We’ll finish by leaving you with a handful of questions to spur thought. Don’t feel pressured to answer every question. Create your own. Again this is more about exhausting your stream of consciousness and less about content.

  • What have I accomplished today (“nothing” is also an answer)?
  • How do I feel about what I’ve accomplished?
  • What decisions would I change if I had the chance?
  • What do I think would be the results if I had the opportunity to change those decisions?
  • What did I learn in the process?
  • What do I want to work toward?
  • How do I feel about my decisions and my path going forward?

We hope that you’ll take the time at the conclusion of this article to reflect on the previous day. While we obviously can’t force you to make a habit of it, we’re hopeful that you’ll entertain the idea.

graphic design for the new indie developer

Image by Lukas Bieri from Pixabay

Coding is the easy part

If we’re honest with ourselves, we’ll admit that coding most software is much easier than the more creative aspects. How many of us seem to effortlessly implement new features, but neglect the user interface and interaction? We’ve definitely fallen into that trap. Even more, as programmers, we tend to devote a disproportionate amount of time to writing code, testing, and fixing bugs than we do to streamlining the interface and creating graphics.

We’d argue that in many cases, taking the time to draft out the user interface and design can eliminate many of the tedious coding tasks that we find ourselves in. We can even do away with the late-night hours developing a complicated feature that wouldn’t even be necessary with intuitive and beautiful design.

It’s hard to be creative

We’ll be the first to admit that we’ll find ourselves neglecting graphic design. In fact, many of our clients are interested more in implementing their grand functional vision (especially when it comes to internal, enterprise applications).

It’s funny because all we hear is the now, almost old adage “marketing is everything”, however, we tend to totally throw it out the window when it comes to execution. We totally get it though. In our case, when we first started out, we were only technically savvy. We didn’t even know how to design graphics for our games and our interfaces. It’s an intimidating task.

Getting started with design

Our recommendation to the indie developer (more specifically, the indie game developer), is to dip your toes into pixel art. It’s a friendly introduction to graphic design and it goes a long way to making your applications look polished.

Backgrounds, buttons, and even animations are incredibly easy to whip up in no time. We’ve always been intimidated by the professional graphic design software. The cost and the learning curve is high (and subjective). But like most other skills, devoting the time (and building habits) will reap rewards (e.g. more app downloads!).

Take a break from coding and start designing

To wrap up, after finishing this article (and sharing it!), jump on the App Store of your choice and download one of the pixel art apps. Stop neglecting what you’ve put aside for tomorrow and start designing basic graphics. Even the most simple design will improve the look, feel, and ease of use.

We’ve used Pixel Studio on iOS extensively. And while it’s notoriously clunky, the results are excellent. Anyway, we’ll let you get to it!

If you like this article, please comment below! Any and all feedback is greatly appreciate. Stay tuned for another simple (no-BS) write-up on app wire-framing and UX design!

industry outlook series: mobile development for the oilfield

Economic climate demands near-perfection

Every now and then we’d like to take a step back from explicit Swift discussions, and dive into our assessment of opportunities in industries that don’t get much attention. The aim is to provide you with ideas outside of your current frame of reference. This week we’d like to discuss a unique opportunity for mobile development – the oilfield. The following article is brought to you by our energy-focused, sister organization – petrolytic.

For most, the thought of the oilfield brings to mind images of heavy machinery and barren deserts. While appropriate, operations are becoming increasingly digitized with an obsession for tech buzzwords of the month: machine learning, big data, artificial intelligence, etc. You name it; the industry is interested. In fact, operators and oilfield services companies of all sizes are desperate for ways to improve safety, mitigate environmental impacts, and make step-changes in efficiency. The current economic climate and public opinion demands it.

Environmental improvements and efficiency gains are not mutually exclusive

There’s no doubt that green tech and renewable energy is trending; and for good reason too. This doesn’t mean, however, that petroleum products are going away. A transition appears to be inevitable, but it’ll take quite a bit of time (barring some black swan event). In any case, there exists a number of opportunities to “greenify” the oil and gas industry and make it more palatable to the masses. Efficiency gains and environmental improvements are not mutual exclusive. As oil and gas professionals, we’ve always felt we had the responsibility to be good stewards of our land. This brings us to the crux of the article – mobile software for the oilfield.

Many might not know that exploration and production companies, as well as, oilfield services companies have significant R&D spending. Even more, many have dedicated VC funds aimed at the next big innovation. In our opinion, there exists ample opportunity to create value for all stakeholders (mobile app developers, oil companies, civilians, shareholders, state revenue… on and on).

Oilfield app ideas

For example:

  • Improving safety (oilfield priority #1) by implementing a mobile notification system to alert of workers of possible incidents.
  • Applying models on mobile devices to diagnose well issues and improve well surveillance.
  • Reservoir simulation should be available on a mobile device (even if the computations aren’t performed on-device).
  • While obvious, how about a gig-economy setup for truckers, hotshots, and frac crews?
  • AR possibilities are endless: training crews, virtual equipment/process manuals, and even surface facilities layouts

It appears to us that much attention is given to the hot sectors: biotech, social media, and the gig-economy. And while attention given to these sectors, other industries are neglected. Our take is that competition is lighter in this industry.

In conclusion, while the oil industry is moving in the direction of tech innovation, it’s incredibly lacking as a whole. The industry is craving more attention and more creative thinkers. While you might not agree with fossil fuels use, providing the means to improve the value chain is undoubtedly beneficial to all stakeholders.

For more posts like this one, please subscribe to our energy-focused newsletter at petrolytic.

swift 5: gamekit leaderboard

Games on the Apple App Store are abundant. We all know this. That’s why it’s imperative to put on your competitive hat and face the action (a little marketing never hurt also). What better way than to introduce some social dynamics to your game via a competitive leaderboard?

We’ve been busy developing a new game and find it incredibly easy to implement basic social functionality using the native Apple Game Center (with GameKit). Most games use this to some extent, so we wanted to share with you all a quick way to implement a GameKit leaderboard.

For reference, GameKit is the framework that allows us to interact with Apple Game Center. You can read more about it in the Apple Developer Documentation.

Before we get started, we wanted to outline the steps at a high level:

  1. Enable GameKit in your Xcode project
  2. Create a Leaderboard Identifier on App Store Connect
  3. Write some code to read and write to Game Center

Very straightforward. Let’s dive right in.

Enable GameKit in your Xcode project

Start by opening your application and verifying the bundle identifier. To enable GameKit, all that’s required is to click the ‘+ Capability’ button on your target. The steps are illustrated in the image below.

That’s it. Your application is set. Let’s set up the leaderboard in your App Store Connect account.

Create a Leaderboard Identifier

The next step is to create a unique leaderboard on your App Store Connect account. Go through the process of creating an app. Once finished, navigate to the Game Center tab under Features. Click the ‘+’ next to Leaderboard, select a single leaderboard, and populate the required information. We use the com.companyname.appname naming convention for our in-app purchases and Game Center content. Make note of the leaderboard ID as we’ll need to reference it when querying from our application.

Write the Code

The final step is to implement the necessary lines of code. What we want to accomplish:

  1. Authenticate the user with Game Center – Apple suggests we do this immediately
  2. Track a scoring metric and posting the high score – we need to track something (we’ll use a high score for this example)
  3. Load the leaderboard – we need a way to display the leaderboard results

It’s not too difficult to implement, however, there are a few hiccups that can occur along the way, which we’ll discuss below.

Authenticate the user with Game Center

Let’s start by authenticating the user when our root view controller’s view did load.

class GameViewController: UIViewController {
    
override func viewDidLoad() {
        super.viewDidLoad()
        authenticatePlayer()
    }

    func authenticatePlayer() {
        if SWGameManager.sharedGameDataManager.gameCenterDisabled == true {
            presentGameCenterDisabledAlert()
            return
        }
        
        let localPlayer = GKLocalPlayer.local
        localPlayer.authenticateHandler = { (viewController, error) -> Void in
            if ( viewController != nil ) {
                self.present(viewController!, animated: true, completion: nil)
            } else if GKLocalPlayer.local.isAuthenticated == true {
                SWGameManager.sharedGameDataManager.gameCenterDisabled = false
                print("Player is authenticated!")
            } else {
                SWGameManager.sharedGameDataManager.gameCenterDisabled = true
            }
        }
    }
}

This is all the code it takes to authorize a user. The SWGameManager code manages additional app-specific metrics (game mechanics, etc), however, the gameCenterDisabled property is one we’d recommend. For whatever reason, if a user declines to log in to Game Center multiple times, the authenticateHandler method won’t be called anymore. This requires the user to go into their general settings and enable Game Center manually. We track this with a flag and then notify the user if their Game Center is disabled.

Track a scoring metric and posting the high score

If you’re developing a game, then chances are you’re tracking some sort of score. When it comes time to sending the score to Game Center, then you’ll need to implement some variation of the following code:

    func postHighScoreToLeaderboard() {
        if GKLocalPlayer.local.isAuthenticated {
            print("\n Success! Sending highscore of \(score) to leaderboard")
            
            let scoreReporter = GKScore(leaderboardIdentifier: Constants.kGameKitLeaderboardID)
            
            scoreReporter.value = Int64(SWGameManager.sharedGameDataManager.highscore)
            let scoreArray: [GKScore] = [scoreReporter]
            
            GKScore.report(scoreArray) { (error) in
                if error != nil {
                    print("An error has occurred:")
                    print("\n \(error!) \n")
                    self.delegate?.postToHighScoreLeaderboardDidFail()
                } else {
                    self.delegate?.postToHighScoreLeaderboardDidSucceed()
                }
            }
            
        } else {
            self.delegate?.localPlayerNotAuthenticatedToPostHighScore()
        }
    }

What we’re doing here is:

  • Verifying that the user is authenticated
  • Creating a score object using our leaderboard identifier (the same one we used to create the leaderboard on App Store Connect)
  • Reporting the score and handling the output

We rely on delegate methods to handle the different outcomes (the functions labeled self.delegate?). These aren’t necessary but are definitely convenient.

Load the Leaderboard

Finally, it’s time to display the leaderboard. This is incredibly straightforward. All that’s required is to use the following code and implement the required delegate method.

    // Present the leaderboard scene
    func presentHighScoreLeaderboard() {
        if SWGameManager.sharedGameDataManager.gameCenterDisabled == true {
            presentGameCenterDisabledAlert()
        } else {
            let leaderViewController = GKGameCenterViewController()
             leaderViewController.gameCenterDelegate = self // Make sure to implement the delegate method
             leaderViewController.leaderboardIdentifier = Constants.kGameKitLeaderboardID
             self.show(leaderViewController, sender: self)
        }
    }

Wrap up

That should do it. Now use a sandbox Apple ID to debug! While this was a relatively simple exercise, Game Center is much more powerful (e.g. tracking player achievements, sharing leaderboards, etc). Check out the Apple Developer Documentation for more information and stay tuned for additional write-ups!

iOS development: new pandemic skills

Here’s yet another suggestion in the sea of unsolicited advice during this pandemic 2020 – learn to code iOS apps. Trust us, we’re speaking from experience. We’re not full-time “coders”. We’re full-time friends, husbands, wives, and entrepreneurs. While some of us our fortunate enough to work from home during this weird time, others aren’t. Whatever the circumstances, we’ve always more time on our hands than we believe. Whether you have 15 minutes every other day or 1 hour every night, dedicate some of that time to iOS development – you’ll thank yourself later.

In fact, research suggests that chunking is a more effective means to learning. That is, the opposite of cramming – spending small, consistent chunks of time yields more results than large, uninterrupted sessions.

In any case, we’d thought we’d share two courses from Udemy that are absolutely invaluable when it comes to picking up iOS development quickly. In fact, these two resources allowed members of our team to make remarkable improvements to their diverse skill set (again, we’re not all full-time coders). The courses aren’t expensive when discounted (we paid $10 per course per person). Promotions are run fairly frequently, so keep checking the website.

Finally, there’s no need for a disclaimer here. We get no referrals or kick-backs of any sort for recommending these videos. We only get the satisfaction of reviewing quality work, recognizing quality work, and hopefully, converting some of you to coders. If we can do it, anyone can do it – seriously.

So, if there was ever a time to pick up iOS development (as a hobby, a side-gig, or career pivot), now is the time.

iOS 13 & Swift 5 – The Complete iOS App Development Bootcamp

Angry Birds, Crossy Road & more: Game Development in Swift 4

swift 5: using plists to store data

Using plists to store data in Swift doesn’t get much attention on the web. Although not the most elegant (or recommended) solution to store data, reading from and writing to property lists is a convenient way to store small bits of data. For example, simple plists can be used to store level data for games.

In the image above, we’ve generated a level set using an external program (think something like python or even Excel). The plist can be dragged-in to any Xcode project and referenced via a few simple lines of code.

Note: you cannot modify a plist included in the main bundle (i.e. dropped into the project as a resource). You’ll need to copy the file over into the users’ documents directory.

Modifying the plist is pretty straightforward. First, check to see if the plist exists in the documents directory. If not, copy it over, otherwise, reference the file.

func reloadData() -> Bool{
        if (try? levelDataURL().checkResourceIsReachable()) == nil {
            guard let originalFile = Bundle.main.url(forResource: Constants.kLevelDataFileName, withExtension: ".plist") else {
                fatalError("Could not locate level data")
            }
            
            do {
                let originalContents = try Data(contentsOf: originalFile)
                try originalContents.write(to: levelDataURL(), options: .atomic)
                print("Made a writable copy of the level data at \(levelDataURL())")
                return reloadData()
            } catch {
                print("Couldn't copy level data to documents directory")
                return false
            }
        } else {
            if let data = try? Data(contentsOf: levelDataURL()) {
                let decoder = PropertyListDecoder()
                do {
                    levels = try decoder.decode([Level].self, from: data)
                } catch {
                    print("Error loading level data")
                    return false
                }
            }
        }
        return true
    }

You’ll notice a [Level].self reference inside the decoder.code function. In order to decode the property list, you’ll need to define a class that represents the object in the list. Level is the Codable class that can be mapped to the plist.

class Level: Codable {
    var number: Int = 0
    var completed: Bool = false
    var available: Bool = false
    var score: Int = 0
    var speed: Float = 0.0
    var radius: Float = 0.0
    var feedspeed: Int = 0
    var path: [Int] = []
    var time: Int = 0
    var music: String = ""
    var musicStartTime: Int = 0
    var specials: [String] = []
    var orbital_types: [String] = []
}

Now that we’ve successfully copied over the plist and created an object that describes the each element in the plist array, we can also modify this copy.

       let encoder = PropertyListEncoder()
        
        do {
            guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last else {
                fatalError("Documents directory not found in application bundle.")
            }
            let url = documentsDirectory.appendingPathComponent("\(Constants.kLevelDataFileName).plist")
            print(url)
            let data = try encoder.encode(newLevels)
            try data.write(to: url)
        } catch {
            print("Error saving results: \(error)")
        }

You’ll notice a newLevels reference in the encoder.encode function. This is an array of Level objects that conform to the plist format. You’ll be required to save the whole plist any time you make changes (even to a single element). It should be pretty apparent why this is pretty clunky and not recommended, however, it’s a convenient way to store small chunks of data that don’t need to be modified often.

Happy coding!

swift 5: sfsymbols tint color and spritekit

Here’s a minor annoyance. Have you tried changing the color of an SF Symbol and initializing an SKTexture only to have the color change fail? In case you’re unaware, iOS 13 introduced SF Symbols.

https://developer.apple.com/design/human-interface-guidelines/sf-symbols/overview/

These are handy vector graphics for standardized purposes (think using it for an email button, close button, home button, etc). They’re incredibly convenient and consistent with the overall feel of iOS.

In any case, when we tried to add a home button to our iOS game using SpriteKit SKTexture, we noticed the color wouldn’t change. We assume this a bug considering it behaves properly with UIImage.

To cut to the chase, if you’re applying an SF Symbol to an SKTexture and want to change the tint color, the following is a decent work around (although not perfect). Hopefully this gets updated!

        let systemImageName = "house.fill"
        let largeConfig = UIImage.SymbolConfiguration(pointSize: 16, weight:.ultraLight)
        
        guard let systemImage = UIImage(systemName: systemImageName, withConfiguration: largeConfig)?.withTintColor(UIColor.red) else { return }
        guard let systemImageData = systemImage.pngData() else { return }
        guard let systemImageTinted = UIImage(data: systemImageData) else { return }
    
        let texture = SKTexture(image: systemImage)

swift 5: memory leaks and closures

While certainly nothing compared to conventional memory management, one frustrating aspect of finishing up your iOS app is discovering runaway memory issues.

One primary source is with respect to closures. From the Swift Programming Reference Manual:

Closures are self-contained blocks of functionality that can be passed around and used in your code…

Closures can capture and store references to any constants and variables from the context in which they are defined. This is known as closing over those constants and variables. Swift handles all of the memory management of capturing for you.

https://docs.swift.org/swift-book/LanguageGuide/Closures.html

This last bolded-statement is technically correct, but not without caution. Closures can capture and store references. The implication being a possible Automatic Referencing Counting Cycle. Put simply, Swift can inadvertently create a referencing loop between the object passed to the closure and the object calling the closure. Below is a diagram illustrating the point:

We’ve run into this issue when using SpriteKit and SKActions. Take for example, the following function:

func run(_ toPoint: CGPoint speed: TimeInterval) {
        let move = SKAction.move(to: toPoint, duration: speed)
        self.run(move) {
            self.jump()
        }
    }

In many cases, calling self.jump() will result in a memory leak given the strong reference. The solution to this memory leak:

func run(_ toPoint: CGPoint speed: TimeInterval) {
        let move = SKAction.move(to: toPoint, duration: speed)
        self.run(move) {
            [weak self] in
            guard let strongSelf = self else { return }
            strongSelf.jump()
        }
    }

And there you have it. A simple solution to a nagging issue we all face at some point. Hope this helps.