Android IP Subnet Practice App – Part 1 – External Libraries

I started app development on iOS, Swift and Xcode, so naturally I was used to Cocoa Pods to get external libraries. Android Studio (with Kotlin) has a similar method, but of course it’s a bit different. I’m no Android expert but I’ll share my learnings so far trying to put together an app that allows the user to practice calculating IPv4 subnets. If you’re not familiar with those, they are a crucial skill to understanding TCP/IP networking.


Just to get a very basic app working, we’ll build an experimental layout in order to test and see if the subnetting code is working. The basic idea is to get something that looks like this:

Subnet Practice Concept App

The top element is a text field that captures the user’s input, while the bottom element is a button that runs the code to find the “network address”, or the first IP address in a subnet, given an IP address and subnet mask. Above, we can see that from “”, the network address “” has been calculated after “TEST” was pressed. That’s what we’re shooting for.


We’ll create these three simple elements on a Relative Layout in activity_main.xml like this:

<RelativeLayout xmlns:android=""

        android:text="" />

        android:layout_marginTop="60dp" />

        android:text="Test" />


Hopefully this is pretty simple – it just creates the three elements and lays them out vertically in the center of the screen.

Adding an external library

Googling around, I found an IP address processing library on Github here:

On the Github page, it explicitly states the Maven Central (a large repository of libraries, connectivity to it is built-in to Android Studio) group and artifact ID’s, as well as the versions:

  • Maven group id: com.github.seancfoley
  • Maven artifact id: ipaddress
  • Maven versions: 2.0.2, 3.0.0, 4.3.3, 5.3.3

We can take this information and put a line in the app-level build.gradle file to download and install the library. Find the dependencies section (usually at the bottom) and add this line:

dependencies {
    //Others here removed for brevity
    implementation 'com.github.seancfoley:ipaddress:5.3.3'

Sync the gradle file and the library should be installed!

Kotlin code

In MainActivity.kt, we’ll connect to the layout elements and add logic. Make sure to enable view binding. Then we’ll write an onCreate function that looks like this:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {

        val binding = ActivityMainBinding.inflate(layoutInflater) #view binding
        setContentView(binding.root) #view binding

        val et = binding.edittextEntry #grab the EditText
        val r = binding.textviewResult #grab the TextView (result)
        val b = binding.buttonTest     #grab the Button

        b.setOnClickListener() {
            val str = et.text.toString() #get text from EditText
            val netAddr = IPAddressString(str).toAddress().toZeroHost().toString() #Magic to calculate network address
            r.text = netAddr #set TextView (result) to network address

This line:

val netAddr = IPAddressString(str).toAddress().toZeroHost().toString()

…takes whatever string is in the EditText and does these steps:

  • IPAddressString(str) turns the string into an IP address string, which is necessary for parsing the original string to a properly formatted IP address.
  • .toAddress() converts the string to an IP address object
  • .toZeroHost() finds the lowest IP address in the subnet, usually called the network address or subnet address. This library calls it a Zero Host.
  • .toString() converts the network address back to a string so it can be put in the TextView

This is definitely where the magic is happening in this code.

Hope this was all clear enough. Leave a comment or send me a message if it’s not!

How to Publish Your iOS App on the App Store

Publishing an iOS app on Apple’s App Store is how you make your app readily available to anyone with an iOS device (and Apple Silicon device!) that wants to use it. Your app must pass a review by a human Apple employee, as well as a number of automated checks to ensure compliance with their policies.

Let’s jump right in!

Apple Developer Program

Apple Developer Program portal

In order to publish your app on the App Store, you need to be a part of the Apple Developer Program which costs $99 per year (as of 2022). You can enroll here. Keep in mind before you enroll, your app needs to be ready. Apple doesn’t allow apps in “beta” status, so if you’re still testing, make sure you finish your app before doing this.

Once you’re enrolled, it’s time to head over to App Store Connect!

App Store Connect

App Store Connect Portal

App Store Connect is, as it’s name suggests, where developers connect their apps to the App Store. You can find it here. To upload an app, click on the “My Apps” button.

On the next page, we’ll click on the “plus” button to add an app, then click on “New App”.

That will pop a window up that asks you to fill out some basic information about your app:

If you’ve come this far with an app, you probably already know what should go here, with the exception of SKU, which you can just make up. Click create, and the app is created.

Version Information

One the first page, you need to fill out a bunch of info for this version of your app. Since you can upload an unlimited number of versions in the future, each version submitted has its own information fields:

Version Info Page

The first step is to take some screenshots on various size iPhones running your app. If your app runs on the simulator, you can just use that.

There are a number of other fields, such as “Promotional text”, “Description”, “Keywords”, “Support URL”, and some others which should all be pretty self-explanatory. There’s a little question mark button by each one to help. The most important thing on this page, though, is the build:

You should be able to find the builds you have uploaded to App Store Connect under the “TestFlight” tab up at the top. How do you upload a build? There are a couple different ways, but I did it through Xcode. From your project in Xcode, go to “Product” –> “Archive”. It will first go through an archive process then bring you to this screen:

Clicking through “Distribute App” and a couple more screens will run though some checks and upload to App Store Connect (not the App Store!). For this to work you need to have registered your valid Apple Developer Program account under Xcode –> Preferences –> Accounts. Also if this your second or more times uploading, make sure to increment the build number under Your Project –> General –> Build. The upload process looks like this:

Once this is done, you’ll need to go back to “TestFlight” and you’ll see the build status is “Missing Compliance”:

Click on “Manage” and answer some questions about encryption, and you should be good to go. Back on the “App Store” tab, go down to the build section and select your newly uploaded build.

App Information

The app information section (accessible via “App Information” on the right) requires surprisingly little information about your app. Fill it out and you’re done:

Pricing and Availability

The pricing and availability section just asks if you want to charge for your app, and in what countries it should be available. This particular app is free, and I made it available everywhere:

App Privacy

The app privacy tab requires that you have a website posting your app’s privacy policy. I made very simple one and published on my blog.


The rest of the tabs are just areas where you can check on your app – ratings, version history and such.

Go back the the version page, and click “Submit”, and your app will be submitted for review!

It’s quite possible that the version you submitted could be rejected for one reason or another. You can communicate with the reviewer via the “App Review” tab on the left (it shows up when there’s feedback from Apple). Be sure to come back and answer their questions, concerns or requests.

Good luck!

How To Add Google AdMob To Your iOS App

Google AdMob is an advertisement network for mobile apps, offered by Google. Basically, if you want to show some ads in your app and make money, you can use AdMob for that. Of course there are other options, but Google is certainly a trusted name in the business. Today we’ll look at how to add AdMob to an iOS app that I created for practicing times tables. You can see how the app was created here:

iOS Times Tables App – Part 1

Let’s get started!

Create a new app in AdMob

If you haven’t signed up for AdMob yet, check out how I did that for the Android version of this app. Assuming you have already signed up, go to We’re going to create a new app, so from the home page click “Add App”:

AdMob Home Page

Then we’re going to give AdMob a few basic details about the app:

App successfully created!

The app now has its own page in AdMob. The plan is to create a basic banner on the practice page, so we’ll create a single “Ad Unit”. Click on “Add Ad Unit”:

Make sure to select “Banner” on this page:

Give it a name on the next page and click “Create ad unit”:

We’ve successfully created an app and a place to show ads within it! Now on to the next step, integrating the Google AdMob SDK.

Installing the AdMob SDK

We’re going to do this with CocoaPods, as it’s the easiest and quickest way (in my humble opinion) to get external stuff. If you don’t have CocoaPods, check out their installation guide. Assuming CocoaPods is installed, we’re going to add CocoaPods to the Times Tables Xcode project that we used to create the app by creating a Podfile. CocoaPods describes this file in their Adding Pods to an Xcode Project guide.

From the terminal, cd your way to root directory of the app. Create a file called Podfile that looks like this, according to the Google AdMob SDK quick start guide:

target 'TimesTables' do

pod 'Google-Mobile-Ads-SDK'


If you haven’t updated CocoaPods in a while, you might need to update:

sudo gem install cocoapods

Then run this command to install the SDK:

pod install --repo-update

At this point, the SDK should be installed! You’ll now need to abandon the project file and start using the newly created workspace file called TimesTables.xcworkspace.

The next step is to edit the project’s Info.plist file to include your AdMob app ID. Following the same Google AdMob SDK quick start guide at section “Update your Info.plist”, we’re going to copy and paste the long XML snippet they show there into Info.plist.

You can edit the plist file from Xcode, but I found it hard to copy and paste anything. I’d recommend just opening with an external editor like TextEdit and pasting it in that way. Info.plist is not in the app’s root directory, it’s in a directory that should have the name of your app that holds your swift files. The directory for this particular app is called TimesTables.

You’ll need to find your AdMob app ID from the AdMob console and replace the dummy one they show here. Your app ID can be found from the “All Apps” AdMob page I showed at the very top of this post.

Now that we have made the required plist changes, we’ll add this snippet to didFinishLaunchingWithOptions in AppDelegate.swift, or more likely, if you’re on iOS 13 or above it’ll be in the SceneDelegate.swift in willConnectTo:

GADMobileAds.sharedInstance().start(completionHandler: nil)

Make sure you import the SDK at the very top of the file to which you added the above snippet:

import GoogleMobileAds

We have successfully downloaded and installed the AdMob SDK in our app!

Showing ads in the ad unit

Our next step is to actually show some ads in the ad unit we created in AdMob. Following Google’s AdMob iOS guide, we’ll add a new global variable to hold the banner. Add this to the top of the TableViewController (see the app code if you need) like this:

import GoogleMobileAds //Import the SDK

class TimesTableViewController: UIViewController {

var bannerView: GADBannerView = GADBannerView(adSize: GADAdSizeBanner) //Create the banner

//class continues from here

Then we’ll write a function to set it up. I used programmatic constraints with autolayout here but you can do anything you want to position it:

func setupBanner() {
    view.addSubview(bannerView) // Add to the view
    bannerView.translatesAutoresizingMaskIntoConstraints = false //Turn on autolayout
    bannerView.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor).isActive = true // X: same as view center
    bannerView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true // Y: attach bottom to view bottom
    bannerView.adUnitID = "ca-app-pub-3940256099942544/6300978111" //Google test banner ad unit ID
    bannerView.rootViewController = self //Google says do this so we do it
    bannerView.load(GADRequest()) //load an ad

Make sure to call this function from viewDidLoad:

override func viewDidLoad() {
    //There's more stuff here in the actual app, but you get the idea.

Try it out!

Our banner is looking great!

The Times Tables App running in the iOS simulator

iOS Swift – Building a Times Tables App – Part 4

Today is a good day. We’re going to finish the iOS times tables practice app we started a while ago. The first three parts are here:

iOS Times Tables App – Part 1
iOS Times Tables App – Part 2
iOS Times Tables App – Part 3

The full code for this app is on my Github page:

Today we will be adding the actual times tables flashcard functionality to the app.

Add the UI elements

As it turns out, you don’t really need to use the init functions I used in part 1. Oh well, live and learn. You can just add them at the top of your class as global variables like this:

//Displays the question
let questionLabel:UILabel = {
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    label.text = ""
    label.numberOfLines = 2
    label.textAlignment = .center
    label.font = UIFont.preferredFont(forTextStyle: .title1)
    label.adjustsFontForContentSizeCategory = true
    return label
//Displays the answwer
let answerLabel:UILabel = {
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    label.text = ""
    label.numberOfLines = 2
    label.textAlignment = .center
    label.font = UIFont.preferredFont(forTextStyle: .title2)
    label.adjustsFontForContentSizeCategory = true
    return label
//Either shows the answer or goes to next question
let button:UIButton = {
    let button = UIButton(type: .system) as UIButton
    button.translatesAutoresizingMaskIntoConstraints = false
    button.titleLabel?.font = UIFont.preferredFont(forTextStyle: .title2)
    button.titleLabel?.adjustsFontForContentSizeCategory = true
    button.setTitle("Show Answer", for: .normal)
    return button

//These are variables we'll need to keep track of the app state
var mode:String = "normal"
var table:Int = 0
var multiplier:Int = 0
var selectedTable = 0
var maxMultiplier:Int = 0
var lastMultiplier = 0
var answerShowing = false

We add three UI elements – questionLabel, answerLabel, and button. Each one does what it sounds like, and button will either show the answer or move on to the next question. Here’s the non-UI variables and what they will do:

  • mode is either “normal” or “random”. Normal starts the multiplier at 2 and goes to until maxMultiplier, then goes back to 2. Random picks a random multiplier between 2 and maxMultiplier.
  • table holds the current table being practiced. In all tables mode, it will be incremented up to 9, then go back to 2.
  • multiplier is the second number in a multiplication question.
  • selectedTable holds the table the user originally selected. If it’s anything other than 0 (the user didn’t select a table), selectedTable will be the same as table since the table won’t change. If selectedTable is 0, table will be incremented or changed randomly, depending on the mode. selectedTable needs to stay the same so that the app knows whether a table was selected or to practice them all.
  • maxMultiplier indicates how far up the user wants to practice in the table or tables. Defaults to 12.
  • lastMultiplier holds the value of the last multiplier. This exists to solve a problem where the same multiplier is selected multiple times in a row in random mode. Using a while loop, we can check if the newly selected multiplier is different from the last one. No need to practice the same question twice in a row.
  • answerShowing tells the app whether the answer is showing or not. Lets us control what code to run when the button is pressed, and what text to put on the labels.

These all have dummy values, because their actual values will be set in viewWillAppear. The UINavigationController reuses old UIViewControllers, so this code only gets run once. viewWillAppear runs every time the view shows, so we’ll set values there.

Layout the UI elements

Like last time, we’ll run several functions to create autolayout constraints for the UI elements, to put them in their proper spots. The viewDidLoad function looks like this:

override func viewDidLoad() {

Now we’ll create each of those functions:

func setupQuestion() {
    questionLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -(view.frame.height * 0.1)).isActive = true
    questionLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true

func setupAnswer() {
    answerLabel.topAnchor.constraint(equalTo: questionLabel.bottomAnchor, constant: view.frame.height * 0.1).isActive = true
    answerLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true

func setupButton() {
    button.topAnchor.constraint(equalTo: questionLabel.bottomAnchor, constant: view.frame.height * 0.2).isActive = true
    button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    button.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside)

Basically everything here is attached to the questionLabel, which we have constrained to 10% above the center Y of the view per -(view.frame.height * 0.1). answerLabel is 10% below that, while button is 20% below. The last line of the button function adds a function called buttonPressed as the function to run when the button is pressed.

Add the logic

As I mentioned earlier, we need to set the global variables’ values in viewDidAppear. It looks like this:

override func viewWillAppear(_ animated: Bool) {

    //Show the nav bar
    self.navigationController!.navigationBar.isHidden = false

    //give the global variables some default values.
    table = 2
    multiplier = 1
    selectedTable = 0
    maxMultiplier = 12
    lastMultiplier = 0
    answerShowing = false

    //Get the user's specified table, if it exists. 0 means no selected table
    if let userTable = UserDefaults.standard.value(forKey: "table") as? Int {
        if userTable != 0 {
            table = userTable
        self.selectedTable = userTable
    //Get the user's specified max multiplier, if it exists. 0 means no selected multiplier
    if let multi = UserDefaults.standard.value(forKey: "multiplier") as? Int {
        if multi != 0 {
            maxMultiplier = multi
    //Get the mode
    if let practiceMode = UserDefaults.standard.value(forKey: "mode") as? String {
        mode = practiceMode
    //Run nextQuestion once at the start.

I added comments inline for this one. Please let me know in the comments if anything is not clear.

At this point, all of our values are set. We need to write out nextQuestion, as it is called in the last line. nextQuestion looks like this:

func nextQuestion() {
    answerLabel.text = "" //Clear the answer
    if mode == "normal" {
        multiplier += 1 //Increment the multiplier every time
        if multiplier > maxMultiplier { 
            multiplier = 2  //Go back to 2 if at max
            if selectedTable == 0 {
                table += 1 //Increment table if in all tables mode and current table is finished (multiplier at max)
                if  table == 10 {
                    table = 2 //Go back to table 2 if all tables finished.
    } else {
        //This is random mode
        lastMultiplier = multiplier
        if selectedTable == 0 {
            table = Int.random(in: 2...9) //If no selected table, get a random one from all tables
        //Get a new multiplier until it's different from the last one, avoids duplicate question.
        while multiplier == lastMultiplier {
            lastMultiplier = multiplier
            multiplier = Int.random(in: 2...maxMultiplier)
    questionLabel.text = "\(table) x \(multiplier) = " //Display question.
    answerShowing = false  //Answer no longer showing
    button.setTitle("Show Answer", for: .normal) //Change button text to "Show Answer"

I added comments inline for this one too. The logic here should take care of all use cases.

Now we’ll write the function to show the answer:

func showAnswer() {
    answerLabel.text = "\(table * multiplier)"
    answerShowing = true
    button.setTitle("Next Question", for: .normal)  

This one is short and sweet. Just show the answer, set answerShowing to true, and set the button text to “Next Question”.

Finally, the code that runs when the button is pressed:

@objc func buttonPressed() {
    if answerShowing {

If the answer is showing, run nextQuestion. If not, run showAnswer.

We’re done!

Try it out!

Things are looking good! Be sure and try all modes and variables you can think of 🙂

iOS Simulator in Xcode

iOS Swift – Building a Times Tables App – Part 3

In two previous posts, we first added the UI elements and then added a bit of logic to make the initial view of the app work. You can find those posts here:

iOS Times Tables App – Part 1
iOS Times Tables App – Part 2

The full code for the app can be found on my Github page:

Today we’re going to add a UINavigationController as well as a second view controller for the actual times tables flash card view.

Adding a UINavigationController

UINavigationController is a handy object available in UIKit. It allows us to put a navigation bar that persists on the screen even as the user changes from one UIViewController to another. By default, it will come with a functioning “back” button.

Since we’re taking a programmatic approach for pretty much everything except adding UIViewControllers, we need to delete the storyboard entrypoint and add one from code. It shows up as a big arrow pointing to the initial UIViewController:

Storyboard Entry Point in Xcode

Once we have it selected (you can click on either the arrow on the canvas or on the one to the left), just hit delete and it’s gone. While we’re in the storyboard, make sure the main view controller has “Storyboard ID”, you can add it from the identity inspector. I called mine “homeVC”:

Identity Inspector for UIViewController

The next step is to add the UINavigationController to the app as well as an entry point from code. If you are developing for iOS 13 and onward, the place to do this is in SceneDelegate.swift. It used to be AppDelegate.swift, but no longer. We’ll add our code to SceneDelegate, in the function willConnectTo. The top of my SceneDelegate.swift file looks like this:

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow? //Gotta add this reference to the app window

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = scene as? UIWindowScene else { return }

        //Adding the UINavigationController here
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let vc = storyboard.instantiateViewController (withIdentifier: "homeVC") as! ViewController
        let navigationController = UINavigationController(rootViewController: vc)
        window = UIWindow(windowScene: windowScene)
        window?.rootViewController = navigationController
        //End of custom code

        guard let _ = (scene as? UIWindowScene) else { return }

In the first couple lines, we grab references to the storyboard and the home UIViewController. Then we create a UINavigationController, and add the home UIViewController as the root view controller. In the last three lines, we start up the window, make it visible and make the UINavigationController the root view controller for the window (yes, two roots). That should replace the storyboard entrypoint as well as add a navigation controller.

Add a second UIViewController

We’re going to use the storyboard to add a second UIViewController. Click the “+” button at the top left and a view controller:

Adding a UIViewController from the storyboard

Then we need to connect to it a swift file. Over on the left side where all the rest of the project files are, right click on the “view” folder and click “new file”. Create a “Cocoa Touch Class”:

Creating a Cocoa Touch Class

Let’s call it “TimesTableViewController”. Click through and create. The last step is to connect the newly created swift file to the newly created UIViewController on the storyboard. We can do that from the storyboard by clicking on the UIViewController and going to its identity inspector and changing the class to the new class we just created, and be sure to give it a storyboard ID:

Connecting a swift file to UIViewController

And our second UIViewController is complete. Now we just need to add code to jump to this view (or rather, push it on to the UINavigationController, to be precise) when the user taps the start button. Please check the github code or previous posts if you’re not sure what I’m talking about here. Let’s add this snippet to startButtonTapped:

let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let ttvc: TimesTableViewController = storyBoard.instantiateViewController(withIdentifier: "ttVC") as! TimesTableViewController
self.navigationController!.setViewControllers([self,ttvc], animated: true)

This looks pretty complicated, but it’s mostly just some magic that Apple wants you to do when you’re pushing a new view controller to the navigation controller. Lastly, I didn’t find that I wanted the navigation bar to show up on the home view controller, just the times tables one. So I added this to my code in the (home) ViewController:

override func viewWillAppear(_ animated: Bool) {
    self.navigationController!.navigationBar.isHidden = true

This just tells the navigation bar to be hidden when the view appears.

Try it out!

The main view is unchanged, but when we click start, we head to the next view! And there’s a back button! And it works!

Hope you liked it. Next time we’ll code in the times tables view. Stay tuned!

iOS Swift – Building a Times Tables App – Part 2

Last post, we put together the UI layout for a times times tables app in Swift using Xcode. The UI elements all work and are in their correct positions, but there’s no logic to make them do anything. Today we’ll add a dash of logic to the home screen so that we can gather up all the information we need to show the user the times tables flash cards they want to see. You can find parts 1 and 3 of this series here:

iOS Times Tables App – Part 1
iOS Times Tables App – Part 3

To really understand what I’m talking about in this post, you’ll either want to look at the last post (link above) or take at the code for the ViewController in my github account:

Adding variables for selected values

There are three different values that the user could potentially provide to the app, and we need to account for all of them. The first is the table – for example, if the user wanted to practice 3×2, 3×3, 3×4 and so on, they would provide 3 in the “table” field. The second is the max multiplier, which is the second number. In the Android version, we set the default to be 12, we’ll keep with that. But the user can change the default by entering something in the max multiplier field. The last is the mode – normal or random. We’ll add some global variables at the top of the class, just below the UI elements variables:

var currentMode:String {
    get {
        if let mode = UserDefaults.standard.value(forKey: "mode") as? String {
            return mode
        } else {
            return "normal"
    set {
        UserDefaults.standard.setValue(newValue, forKey: "mode")
var currentTable:Int {
    get {
        if let table = UserDefaults.standard.value(forKey: "table") as? Int {
            return table
            return 0
    set {
        UserDefaults.standard.setValue(newValue, forKey: "table")
var currentMultiplier:Int {
    get {
        if let multiplier = UserDefaults.standard.value(forKey: "multiplier") as? Int {
            return multiplier
            return 0
    set {
        UserDefaults.standard.setValue(newValue, forKey: "multiplier")

If you’re not familiar with “computed properties” in Swift, this probably looks pretty foreign. Basically, a computed property is a variable that doesn’t hold a value. Normally, variables hold values. Instead, you write code to get and set the value. The get and set code runs when elsewhere in your code you write something that either gets or sets the variable’s value. That’s why there’s a get and set part (technically set is optional).

The reason we’re doing this here is because we want the values to be stored in the UserDefaults file. UserDefaults is just a text file where you can store some key-value data that you can access even after the app or phone restarts. Because of that persistence, the app can “remember” values that were entered last time so the user can avoid re-entering their favorite table, max multiplier or mode. We’ll also be able access the values from the next view in the app with the actual flash cards without having to “send” it like in Android. For getting, it also lets us account for the possibility that there will be no value in UserDefaults, and return a default in that case. The get blocks return “normal” by default for the mode, and 0 by default for the table and multiplier.

Populate the table and max multiplier

We’ll use the code we just wrote to put values in the table and max multiplier text fields. In the setupInputs function we’ll add the following snippet:

if currentTable != 0 {
    tableInput.text = String(currentTable)
if currentMultiplier != 0 {
    multiplierInput.text = String(currentMultiplier)

Remember, since currentTable and currentMultiplier are computed, these lines simply run the get blocks that we wrote earlier for these variables. If the values stored in UserDefaults were not 0, we’re setting the the textfields to be whatever was stored. The reason why we avoid pre-populating 0 is because we’ll use 0 in the startTapped function to mean that the user accepted the defaults and entered nothing. In that case, we don’t need to pre-populate anything. We’ll add this snippet to startTapped:

if let tableText = tableInput.text {
    if let table = Int(tableText) {
        currentTable = table
        currentTable = 0
    currentTable = 0
if let multiText = multiplierInput.text {
    if let multiplier = Int(multiText) {
        currentMultiplier = multiplier
        currentMultiplier = 0
}else {
    currentMultiplier = 0

This code, which runs when the user taps the start button, will grab whatever the user entered in the text fields and runs the set blocks that we wrote earlier. We check first to see if there’s any text at all, then to see if it will properly change to an Integer. If both of those pass, we set the entered value to UserDefaults. If either fails, we set the UserDefault value to 0.

Setting the mode

In Android, we were able to create a radio group with two multually exclusive options, normal and random. In Swift and UIKit, no such thing exists. So what we’ll use is UISwitch, which is a little switcher button thingy. We already laid them out in the last post, but we need to make sure they work right. When one is selected, the other can’t also be selected. We’ll achieve that with the following code in modeTapped:

modes.forEach { $0.isOn = false }
sender.isOn = true
switch sender.tag {
case 0:
    currentMode = "normal"
case 1:
    currentMode = "random"
    currentMode = "normal"

That first line simply unchecks both of the UISwitch elements in the modes array. Remember creating that array? It just holds the switches so we can loop through them. Then we turn the switch on for whichever switch fired the function, followed by setting currentMode to either “normal” or “random” based on whether the sender’s tag is 0 or 1. We set the tags when we created the switches, you might have forgotten 🙂

We’ll “remember” whatever setting the user selected last time they opened the app by adding this snippet to setupModes:

if currentMode == "random" {
    randomMode.isOn = true
    normalMode.isOn = true

This once again pulls the mode value from UserDefaults.

Dismiss keyboard

I ran into an issue when I realized I couldn’t dismiss the keyboard once it appeared for the text fields. I got it to go away by adding UITextFieldDelegate to my ViewController’s class declaration so it looks like this:

class ViewController: UIViewController, UITextFieldDelegate {

And for each text field, made the ViewController the delegate in the setupInputs function:

tableInput.delegate = self
multiplierInput.delegate = self

Finally, I added this function which is available if your ViewController has been made the UITextFieldDelegate:

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    return true

It basically just tells the keyboard to go away when return is tapped, if they keyboard appeared for a text field.

Try it out!

Our app in the Xcode iOS simulator

Not a whole lot about the look has changed since the last post, but one thing you can do is print the values of currentTable, currentMultiplier and currentMode in the console. You can also enter some, press start, and then close/restart the app. You should be able to see the values persist.

Stay tuned for the next post, where we’ll create the screen for the flash cards!

iOS Swift – Building a Times Tables App – Part 1

Previously, we built an Android times tables practice app in Kotlin, as well as a backend-only web times tables app in Python. Today we’re going to port this app to Swift so it can work on iOS for an iPhone as well. Let’s get started! You can find parts 2 and 3 of this series here:

iOS Times Tables App – Part 2
iOS Times Tables App – Part 3

At the time of writing, this was done in Xcode 12.5.1 and Swift 5.4.2. All the code for this app can be found on my github account:

Create a project in Xcode

We’re going to create an iOS app in Xcode, so make sure you select “iOS” in the Xcode new project window:

Xcode New Project Window

There are, in fact, many different ways to write an app in Xcode/iOS/swift. As a matter of complete personal preference, I like doing everything “programmatically”. In iOS development you have two choices: use Interface Builder or programmatically. Interface Builder uses the story board to create UI objects/elements, while programmatic creates the same elements from swift code without using Interface Builder. I happen to prefer the latter.

The only thing that is really difficult to create from code is a UIViewController, so I typically add those from the storyboard. Since Apple gives us the first UIViewController, we’ll jump right into creating the UI elements.

Create the UI objects

We’ll first create global variables to hold our UI elements so we can access them from anywhere in the class, like this:

let mainLabel:UILabel
let subLabel:UILabel
let tableInput:UITextField
let multiplierInput:UITextField
let normalMode: UISwitch
let normalLabel: UILabel
let randomMode: UISwitch
let randomLabel: UILabel
let startButton: UIButton
var modes: [UISwitch] = []

I’ll explain what each one does:

  • mainLabel: a title-like piece of text to show the name of the app.
  • subLabel: some text that tells the user to enter a table or leave it blank to practice all tables.
  • tableInput lets the user select a specific table to practice.
  • multiplierInput lets the user specify how far up they want to practice. The default is to practice to 12, but this input allows it to be configured.
  • normalMode: a switch for “normal mode” which practices in sequence.
  • normalLabel: a label attached to the switch saying “normal mode”.
  • randomMode: a switch for “random mode” which practices randomly.
  • randomLabel: a label attached to the switch saying “random mode”.
  • startButton: the button to begin practicing.
  • modes: an array to hold the two switches, more on that in the next post.

Now that we have these created, we’ll add a couple of functions that allow us to create objects to put in these variables, without ever touching Interface Builder. They look like this:

convenience init() {

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)

I won’t go into how these work, as it’s a bit distracting from the app building. Suffice to say they let us create UI objects programmatically.

Our objects can be created in the required init? function before the line with super.init is run. The way I typically create objects is using closures, which is just a function without a name. You can assign whatever the closure returns to a variable. So I just create a bunch of closures that create the objects and assign them to the global variables. This next bit is long, but it’s just a bunch of boilerplate creating these elements/objects the way that I wanted them. The required init? function now looks like this:

required init?(coder aDecoder: NSCoder) {
    mainLabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.text = "James McClay's Times Tables!"
        label.numberOfLines = 2
        label.textAlignment = .center
        label.font = UIFont.preferredFont(forTextStyle: .largeTitle)
        label.adjustsFontForContentSizeCategory = true
        return label
    subLabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.text = "Enter a table to practice,\n or blank for all:"
        label.numberOfLines = 2
        label.textAlignment = .center
        label.font = UIFont.preferredFont(forTextStyle: .title2)
        label.adjustsFontForContentSizeCategory = true
        return label
    tableInput = {
        let input = UITextField()
        input.translatesAutoresizingMaskIntoConstraints = false
        input.placeholder = "All Tables"
        input.borderStyle = .bezel
        input.keyboardType = .numberPad
        return input
    multiplierInput = {
        let input = UITextField()
        input.translatesAutoresizingMaskIntoConstraints = false
        input.placeholder = "Max Multiplier (12)"
        input.borderStyle = .bezel
        input.keyboardType = .numberPad
        return input
    normalMode = {
        let mode = UISwitch()
        mode.translatesAutoresizingMaskIntoConstraints = false
        mode.tag = 0
        return mode
    normalLabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.text = "Normal Mode"
        label.font = UIFont.preferredFont(forTextStyle: .body)
        label.adjustsFontForContentSizeCategory = true
        return label
    randomMode = {
        let mode = UISwitch()
        mode.translatesAutoresizingMaskIntoConstraints = false
        mode.tag = 1
        return mode
    randomLabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.text = "Random Mode"
        label.font = UIFont.preferredFont(forTextStyle: .body)
        label.adjustsFontForContentSizeCategory = true
        return label
    startButton = {
        let button = UIButton(type: .system) as UIButton
        button.translatesAutoresizingMaskIntoConstraints = false
        button.titleLabel?.font = UIFont.preferredFont(forTextStyle: .title2)
        button.titleLabel?.adjustsFontForContentSizeCategory = true
        button.setTitle("Start!", for: .normal)
        return button
    super.init(coder: aDecoder)
    modes = [normalMode, randomMode]

modes = [normalMode, randomMode] is put after super.init because that’s where self is created. I’ll use that array to make sure only “normal” or “random” mode can be selected, both.

Now that we have all those elements created, let’s lay them out on the view.

Using autolayout to put objects on the view

All of the elements created above have translatesAutoresizingMaskIntoConstraints set to false, which means that Autolayout is turned on. Autolayout basically allows a swift developer to put UI elements on the view and have their position dynamically calculated based on the view size and their relative position to other elements.

The way I like to do this is to write a function to hold the code for each logical area, and call each function from viewDidLoad. So my viewDidLoad looks like this:

override func viewDidLoad() {
    self.navigationController!.navigationBar.isHidden = true

First we’ll set up the “labels”, the main one and the sub one. My setupLabels function looks like this:

func setupLabels() {

        equalTo: view.safeAreaLayoutGuide.topAnchor,
        constant: view.frame.height * 0.1
    ).isActive = true
    mainLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    mainLabel.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.8).isActive = true

        equalTo: mainLabel.bottomAnchor,
        constant: view.frame.height * 0.04
    ).isActive = true
    subLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    subLabel.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.7).isActive = true

I really hate how complicated this looks, because it’s not complicated. The autolayout code here is doing just a few basic things:

  • Add the UI element to the view as a subview (it puts the element on the screen).
  • Anchor its y-axis, usually by putting a constraint on the topAnchor. I usually give a constant with that one as well to provide some dynamically-created spacing, with view.frame.height * 0.1.
  • Anchor its x-axis, a lot of times it can just be constrained to the view.centerAnchor.
  • Anchor the width, usually to a percentage of the main view.

Once those constraints are in place, the element will properly show on the screen. That’s really all that’s happening here. If you have any questions, please comment or contact me!

Now let’s create setupInputs:

func setupInputs() {

        equalTo: subLabel.bottomAnchor,
        constant: view.frame.height * 0.04
    ).isActive = true
    tableInput.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    tableInput.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.4).isActive = true

        equalTo: tableInput.bottomAnchor,
        constant: view.frame.height * 0.02
    ).isActive = true
    multiplierInput.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    multiplierInput.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.4).isActive = true

You might have noticed this looks very much like setupLabels. That’s because autolayout requires a great deal of boilerplate but necessary code. I haven’t found a good way to reduce the plates on my boiler for this kind of code, so I end up with a fair amount of it when laying things out programmatically.

Now let’s create setupModes:

func setupModes() {
        equalTo: multiplierInput.bottomAnchor,
        constant: view.frame.height * 0.04
    ).isActive = true
    normalMode.leadingAnchor.constraint(equalTo: tableInput.leadingAnchor).isActive = true
    normalMode.addTarget(self, action: #selector(modeTapped), for: .touchUpInside)
        equalTo: normalMode.trailingAnchor,
        constant: view.frame.width * 0.01
    ).isActive = true
    normalLabel.centerYAnchor.constraint(equalTo: normalMode.centerYAnchor).isActive = true
    normalLabel.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.3).isActive = true
        equalTo: normalMode.bottomAnchor,
        constant: view.frame.height * 0.02
    ).isActive = true
    randomMode.leadingAnchor.constraint(equalTo: tableInput.leadingAnchor).isActive = true
    randomMode.addTarget(self, action: #selector(modeTapped), for: .touchUpInside)
        equalTo: randomMode.trailingAnchor,
        constant: view.frame.width * 0.01
    ).isActive = true
    randomLabel.centerYAnchor.constraint(equalTo: randomMode.centerYAnchor).isActive = true
    randomLabel.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.3).isActive = true

Once again, very similar to the previous ones with one difference. We’re attaching a label to the right edge of each switch. So normalMode has a corresponding normalLabel to explain to the user what the switch is for. The normalLabel.leadingAnchor is constrained to the normalMode.trailingAnchor with some spacing given to constant.

Finally, we’ll set up the start button with setupStartButton:

func setupStartButton() {

        equalTo: randomMode.bottomAnchor,
        constant: view.frame.height * 0.04
    ).isActive = true
    startButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    startButton.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.3).isActive = true

Try it out!

Now that we have all the UI elements created and laid out and constrained, they should fall into place! On the simulator it’s looking good:

The app running on Xcode iPhone Simulator

In the next post, we’ll add some logic so our elements actually do things.

See you next time!

How To Publish An Android App On The Google Play Store

In a previous post, we created a simple app for practicing times tables. Then we added Google AdMob to it to display a basic ad banner at the bottom of the app. Today, we’re going to get the app published and available on the Google Play Store.

Create a developer account

Becoming an official developer with Google costs a one-time $25. It all starts here:

If you already have a google account, just follow the prompts to make your account a developer account.

Developer account creation page

Once your account is a developer account, you’ll need to upload a document that proves your identity.

Identity verification page

Verification usually takes a day or two to complete.

Create an app

Now we’re ready to create our first app on the store.

Play Store Console App Creation

The app creation process takes some time, and if you’re really serious about it, some planning. I won’t show all the screenshots, that would get a little long. The times tables app is very simple so we can move through it pretty quick.

Step 1 – basic details

We’ll need to give it a name, default language, whether it’s a game, and whether it’s paid or free. Be careful on that last one, once it’s set you can’t change it later.

Step 3 – App setup

App setup process

Google wants to know a fair amount about the app before it’s published. Some of it is for their own internal policies or data collection, others are to comply with various laws in the countries the app can be available in.

  • App access – whether your whole app is available immediately or if there is a paywall.
  • Ads – whether your app contains ads or not.
  • Content rating – a questionnaire about the content of your app.
  • Target audience – the age your app might be targeted to.
  • News apps – whether or not your app contains news.
  • COVID-19 – whether or not your app is for tracing COVID-19.
  • Data safety – you must disclose what kind of data your app collects. You also need to provide a link to a privacy policy for your app, so you’ll need to create both the policy and the page if you haven’t already.
  • Select an app category and provide contact details – a few questions about what categories your app falls under.
  • Set up your store listing – see below

Step 4 – Set up store listing

The store listing setup area will collect a bunch of information that is used to build your app’s Play Store page.

Store listing setup page

We need to upload the app icon, along with a feature graphic. A feature graphic is important if the app ever becomes popular and Google wants to feature it on the app store:

Then it’s time for screenshots:

Once we have all that stuff input and uploaded, we should be good on the store listing section. We should now be able to complete the final section to release the app on the Play Store.

Release the app on the Play Store

Now that we’ve done all the work to get the app ready, the “Publish your app on Google Play” section at the very bottom on the app’s main dashboard should be available. You’ll need to skip all the sections about testing and pre-releasing. It looks like this:

First check all countries in “Select countries and regions”, unless you have a reason not to select them all. Then click on the “Create a new release” button. On this page we’re actually going to upload a copy of the app code.

In Android Studio, you can create a bundle from Build –> Generate Signed Bundle:

Creating a Signed Bundle in Android Studio

If this is your first time creating a signed bundle, you’ll need to create a key store. Just fill in the information, it’s part of the X.509 certificate standard so it asks you for a bunch of identifying information:

Make a note of the build file destination, and create the bundle. Then upload the “.aab” file in on this page. After entering some quick details on the release at the bottom, we’re good to go.

We are now finally ready to roll it out to the world! On the Review Release page, we can click “Start rollout to Production”, which means we have completed all preparation steps!

Final release review page

Clicking the rollout button will send the app to Google, where it will be reviewed by human beings to ensure the app is safe/secure/compliant and otherwise OK to release to the world. If all goes well, the app should be available on the store within 3 days, sometimes taking up to 7, according to Google.


As an Indie App Developer, Marketing Terrifies Me

I’ve been working on an app for over 2 years now, and I feel like I’ve done a fair amount of research about how to market an app. Enough to know that I really don’t know how to do it. My chances of launching an app that anyone will download, much less pay for (through in-app purchases, my chosen monetization method), is slim. If you’ve done any research about common ways that apps fail, probably the most common is that the marketing didn’t connect with users, or there wasn’t any marketing done at all.

If you just build it, they definitely won’t come

It seems like there’s a fair amount of indie app developers with no marketing plan at all. No matter how great an idea, no matter how well an app solves a problem, if nobody knows about it they won’t be downloading your app. I think every developer would like to think their app is going to be the next Instagram – it’s so awesome that it simply markets itself.

The truth is, no app markets itself. And the version of Instagram in your head where it was so cool and awesome that no one had to do any marketing is simply an illusion. If you look into how Instagram was created, they had to do a lot of hard work and big changes to get anyone to be interested in it.

For my app, I know if I don’t have at least some kind of plan to market it, I’ll fall into that group of apps that good or bad, never get discovered.

App store optimization – does it do anything?

I understand App Store Optimization (ASO) to be the technique of trying to get your app to come up in search results when users search on the App Store. There are ways that ASO can be quickly applied, for example choosing the correct wording for the title of your app, as well as writing a good description with good screenshots.

But the more effective ASO techniques require hard work, diligence, and time. The app store wants to see, for example, that your app has lots of good reviews, that your app is updated often, and has a lot of downloads before it really starts showing your app in search results.

This presents us a chicken-and-egg scenario. How do you get good reviews and downloads if the App Store wants you to already have good reviews and downloads? I’m thinking that the answer is that ASO is not a good marketing technique by itself. There’s no special words or key phrases you can put in your app’s description that’s going to magically attract users to it. That may have been true early on in the history of the App Store when there weren’t so many apps and app developers. But now there’s lots of competition, and you really have to stand out from the crowd.

How to stand out?

If app marketing takes time and hard work, how do really successful apps launch themselves to popularity within a few days or weeks of launch? That kind of rocket-propelled launch doesn’t happen by accident. It’s almost always part of a carefully planned marketing campaign, using a number of techniques to draw attention to the app’s existence.

I think it’s safe to say that this marketing business is no easy task all by my lonesome, especially when most of my time is spent, you know, building the app. I need some help.

My plan

My plan has two parts:

  1. Do my own social media marketing
  2. Try to get someone with some influence to help

That’s about it. The other person on my team, my wife, has a Youtube channel (, if you’re interested) an Instagram account, and a Facebook page, and we’re going to market the app there.

For my part, I plan to spend a few months to do some groundwork trying reaching out to some influencers that might be interested in promoting my app, and see what they want in return.

We’ll see what happens! Wish me luck!

Swift Classes – You Don’t Really Need To Understand Them.

Of course, that’s not actually true. If you want to become an expert Swift programmer, you absolutely need to understand classes. However, I believe you don’t really need to know that much about classes to get going with them. In fact, the first time you use them you probably won’t even really be aware of it other than there’s a “class” keyword in your code at the top.

Tutorials might have confused you.

At least, I was confused. Most of the explanations I read/watched about classes went something like this:

“A class lets you create a custom object. For example, say you wanted to create an Animal class, you’d do it like this:”

class Animal {
 let greeting = "I am an animal"

“Now you can create multiple Animal instances from the original design you created in Animal, like this:”

let animal1 = Animal()
let animal2 = Animal()
let animal3 = Animal()

“Now create a subclass, that lets you use all of the stuff Animal had, and customize further for this subclass. Our subclass will be Dog:”

class Dog: Animal {
 let species = "I am specifically a dog"

“And now you can create as many Dogs as you want, an army of them in fact, all with the powers of both Animal and Dog:”

let myDog1 = Dog()
let myDog2 = Dog()
let myDog3 = Dog()

print("\(myDog1.greeting). \(myDog1.species)")
print("\(myDog2.greeting). \(myDog2.species)")
print("\(myDog3.greeting). \(myDog3.species)")

And the tutorial would go on to explain properties, methods, etc. That’s super cool, and those are indeed the magical powers of classes and object oriented programming. When I first saw this kind of explanation, the concept totally made sense in my head. I was totally on board with the logic.

But how to use them?

But then I went to try and write an app of my own, and found I had no idea why anyone would ever use classes in actual code. Sure it’s all fun with animals, dogs and cats, but I was way more concerned about how I would get my app to show an image or a button, for starters. That’s the level I was at. But there was the class keyword staring at me when I created a new project in Xcode, without ever writing a single line of code on my own. It appears in the freebie stuff Xcode gives you when you create a fresh storyboard-based project:

class ViewController: UIViewController {

    override func viewDidLoad() {
        // Do any additional setup after loading the view.

Why is class there? And it’s not just a class, it’s a subclass. To be honest, understanding why isn’t really necessary to get your app to fire up for the first time, or to get an image on the screen, or put some basic logic behind a button.

I’ve realized that to create a basic app, you don’t need to worry about creating classes from scratch, or much less create subclasses of your custom classes to use abstract object oriented constructs such as polymorphism or multiple inheritance. The most immediately applicable use of a class is right there in that first bit of code that Xcode populates for you.

There’s a swift class right front of you

If you think about what the Apple developers might have been thinking when they were cooking up Xcode, they can’t possibly know what your app is going to do. At some point, they have to hand some control of the screen to your app. The way they accomplished this was to create UIViewController, which does a bunch of stuff you can’t see to create a blank screen on the phone, ready to be customized for some interesting and unique things your app will do. If you don’t customize UIViewController, all your app will ever be is a blank screen. By creating a subclass of UIViewController (Apple assumes you want to call this ViewController), you can now write your own custom stuff to show beautiful things on the screen. You don’t really realize it, but you’re using inheritance.

The subclassing in this line lets you customize the view:

class ViewController: UIViewController

But where does the handoff take place? When does Apple hand off the view to your app? As it turns out, viewDidLoad() is a function that Apple already wrote. Like the name suggests, it loads up the view. But if you don’t customize it, it’ll just be a blank view of nothing. That’s why you need to “override” viewDidLoad to customize it, so you can start running your own code. That’s what’s happening here:

override func viewDidLoad()

But there’s one last thing to do in your now-overridden viewDidLoad function. Since you overrode it, the original Apple code to load up the blank view won’t run. So you have to run it with:


At this point, you’re finally ready to write your own custom code for your app.

As you keep coding, you’ll realize that subclassing Apple-created classes like this is really helpful when you want to do all sorts of things, and the inheritance concept will make a very real-world kind of sense.

I really think that’s a more realistic approach than an Animal/Dog/Cat example of classes, which makes sense after you’ve had a lot of experience.

I hope that helps! Happy coding!