Category Archives: App Development

How to built a Control Center layout with 25 lines of Swift code

Control Center using GridLayout

Recreating a layout similar to Control Center is easy with GridLayout, a library that uses AutoLayout to organize view in a grid like layout.

The key to building this layout is seing it as a grid with 4 equal columns and 6 equal rows. Placing items on the grid is then a matter of picking the right column and row and the right column span and row span.

    func buildControlCenter() -> UIView {
        var items = [GridItem]()
        items.append(GridItem(buildPanel(), position: Position(rowSpan: 2, columnSpan: 2), margin: 8).stretched())
        items.append(GridItem(buildButton(), margin: 12).stretched())
        items.append(GridItem(buildButton(), row: 1, margin: 12).stretched())
        items.append(GridItem(buildButton(), column: 1, margin: 12).stretched())
        items.append(GridItem(buildButton(), row: 1, column: 1, margin: 12).stretched())
        items.append(GridItem(buildButton(), row: 2, margin: 12).stretched())
        items.append(GridItem(buildButton(), row: 2, column: 1, margin: 12).stretched())
        items.append(GridItem(buildButton(), position: Position(row: 3, columnSpan: 2), margin: 12).stretched())
        items.append(GridItem(buildButton(), row: 4, margin: 12).stretched())
        items.append(GridItem(buildButton(), row: 4, column: 1, margin: 12).stretched())
        items.append(GridItem(buildButton(), row: 5, margin: 12).stretched())
        items.append(GridItem(buildButton(), row: 5, column: 1, margin: 12).stretched())
        items.append(GridItem(buildPanel(), position: Position(column: 2, rowSpan: 2, columnSpan: 2), margin: 8).stretched())
        items.append(GridItem(buildButton(), position: Position(row: 2, column: 2, rowSpan: 2), margin: 8).stretched())
        items.append(GridItem(buildButton(), position: Position(row: 2, column: 3, rowSpan: 2, columnSpan: 2), margin: 8).stretched())
        items.append(GridItem(buildButton(), row: 4, column: 2, margin: 8).stretched())
        items.append(GridItem(buildButton(), row: 4, column: 3, margin: 8).stretched())

        return UIView.gridLayoutView(items: items,
                                     rows: [.fill, .fill, .fill, .fill, .fill, .fill],
                                     columns: [.fill, .fill, .fill, .fill])
    }

You can find the entire sample on GitHub.

If you haven’t already, give GridLayout a try, it can save you time when building complex layouts.

I use GridLayout in several of my games. If you would like to check them out, visit my website.

5 Rules for Creating App Screenshots

Screenshots are one of the crucial ingredients contributing to the success of your app.
Great apps have great screenshots and Store assets. The purpose of the screenshots is to communicate the strong points of your app. Imagine having a pitch your idea in person to someone in person. The sentences you use to describe your app should be the inspiration for your screenshots.

1. Screenshots should surface your content using a compelling narrative

The screenshots should be accompanied by short 3 to 5 words sentences. These sentences should either summarise the focus of the screenshots or tell part of the app story.
Remember: users are motivated by stories and convinced by compelling graphics.

2. Use your best screenshot first

First impressions matter so make good use of the first screenshot slot. Ask yourself If the user only looks at one screenshot, what screenshot should that be? Assume you have only one chance to convince the user and focus on capturing the essence of the app in the first screenshot.

3. Avoid using screenshots of the user interface

Screenshots of settings, options, about us or similar supporting views should not be captured in screenshots. If possible you can even remove elements of the user interface from the screenshots to avoid distracting the user attention. (E.g. remove a distracting back button if it sits on top of aesthetically pleasing content before taking the screenshot). Feel free to break this rule if the user interface is award winning or designed by a renowned artist.

4. Use all available screenshots slots in the Store

If the app does not offer a lot of content use the screenshots for telling a story instead.

E.g.

  • A weather app that only has only a view that displays the weather in your current location, and does not allow seeing the forecast or the weather in other locations: take screenshots during different time of the day and in differ physical locations. Use 3 to 5 screenshots to show the main view with different content while explaining to the user the ideal use case for the app.

  • A note taking app with only one view should focus on how the app can be used instead of enumerating features. The main features of the app should be obvious from the usage scenario.

5. The last screenshot should either be memorable or contain a call to action

Use one of the most attractive screenshots as the last screenshot along with your tag line. Alternatively, use a call to action to instruct the user what to do next.

Rules can only get you so far. To really stand out, feel free to take creative liberties. After all, if your are doing what everyone else is doing, you won’t be any better than the rest.

Follow these rules to improve your Store conversion rate and to make users understand your app faster.

I have used these rules successfully on several of my games that I published in the Microsoft Store and in the App Store. You can find links to all the games that I built on my website: frenzygames.net

Automatic Dependency Injection in Swift

In this article, I’m going to explore several Swift mechanisms that offer similar benefits to Automatic Dependency Injection, and evaluate their strengths and weaknesses.

I’m a big fan of Automatic Dependency Injection.
It saves time, it makes the code cleaner, and it works great for testing.
In the past, I built and used several Dependency Injection libraries, most recently in C# and in Objective-C.

How Does Dependency Injection Work?

Most dependency injection libraries build objects and resolve properties using the built-in language Reflection capabilities.
Swift has limited Reflection capabilities that allows inspecting objects, but not creating objects.

How Is It Done in Objective-C?

One way of overcoming this limitation is to use Objective-C APIs. Doing so requires that all objects that need to be created inherit from NSObject, and I would like to move away from having to use NSObject inheritance for Swift classes.

Let’s Get Started

Consider the following scenario:

  • SoundServiceProtocol protocol
  • SoundService class that implements SoundServiceProtocol protocol
  • Animal and Vehicle
protocol SoundServiceProtocol {
    func makeSound()
}

class SoundService: SoundServiceProtocol {
    func makeSound() {
        print("makeSound was called")
    }
}

class Animal {
    func action() {
        // use SoundService and call makeSound()
    }
}

class Vehicle {
    func action() {
        // use SoundService and call makeSound()
    }
}

Goal: use SoundService in Animal and Vehicle classes in an easy, concise and decoupled way.

1st Approach: Manually Adding Dependencies

class Animal {
    private var soundService: SoundServiceProtocol

    init(soundService: SoundServiceProtocol) {
        self.soundService = soundService
    }

    func action() {
        soundService.makeSound()
    }
}

class Vehicle {
    private var soundService: SoundServiceProtocol

    init(soundService: SoundServiceProtocol) {
        self.soundService = soundService
    }

    func action() {
        soundService.makeSound()
    }
}

Calling code:

let soundService = SoundService()
let animal = Animal(soundService: soundService)
let vehicle = Vehicle(soundService: soundService)

animal.action()
vehicle.action()

While this approach works, I find the infrastructure code to be too lengthy. Furthermore, a parent object that handles the lifetime of a child object must pass along dependencies, making the code lengthier. Even if the parent object does not need the dependency, it still needs to receive it in the init, to use it for constructing the child object.

Take the following example:

  • Class Horn needs the SoundServiceProtocol dependency.
  • Class AdvancedVehicle does not need the SoundServiceProtocol dependency for itself, but it does need it in order to construct the child object.
class Horn {
    private var soundService: SoundServiceProtocol

    init(soundService: SoundServiceProtocol) {
        self.soundService = soundService
    }

    func action() {
        soundService.makeSound()
    }
}

class AdvancedVehicle {
    private var horn: Horn

    init(soundService: SoundServiceProtocol) {
        horn = Horn(soundService: soundService)
    }
}

As you can imagine, the hierarchy of dependencies will grow as the parent and the children objects grow in complexity, resulting in time consuming code to maintain.

2nd Approach: Singleton Service Locator

class ServiceLocator {
    private static var instancePrivate: ServiceLocator?

    public static var instance: ServiceLocator {
        return instancePrivate!
    }

    public private(set) var soundService: SoundServiceProtocol

    init(soundService: SoundServiceProtocol) {
        self.soundService = soundService

        ServiceLocator.instancePrivate = self
    }
}

class Animal {
    func action() {
        ServiceLocator.instance.soundService.makeSound()
    }
}

class Vehicle {
    func action() {
        ServiceLocator.instance.soundService.makeSound()
    }
}

Calling code:

let soundService = SoundService()
let _ = ServiceLocator(soundService: soundService)
let animal = Animal()
let vehicle = Vehicle()

animal.action()
vehicle.action()

This approach moves the verbosity away from each class that needs access to a SoundService. Instead, the singleton ServiceLocator will have to be instantiated once, and afterwards all objects that need access to the service will have to use the static instance variable available on ServiceLocator.

While the code is much shorter than the 1st approach, when used by a consumer, the code used to call the service in each caller classes got bigger:

  • 1st approach: soundService.makeSound()
  • 2nd approach: ServiceLocator.instance.soundService.makeSound()

3rd Approach: Protocol Extensions

Building on 2nd approach, we can take advantage of the Swift protocol extension and the fact that you can define methods and properties that apply for all classes conforming to a protocol.

We define a new protocol named HasSoundService which only contains a computed property that is meant to simplify the access to the ServiceLocator.

protocol HasSoundService {
}

extension HasSoundService {
    var soundService: SoundServiceProtocol {
        return ServiceLocator.instance.soundService
    }
}

Any class that needs access to SoundService must conform to HasSoundService protocol:

class Animal: HasSoundService {
    func action() {
        soundService.makeSound()
    }
}

class Vehicle: HasSoundService {
    func action() {
        soundService.makeSound()
    }
}

Notice that we had to introduce a new protocol HasSoundService and write a computed property in an extension for that protocol. At the same time, each class that needs access to that property must conform the new HasSoundService protocol.

The calling code remains unchanged:

let soundService = SoundService()
let serviceLocator = ServiceLocator(soundService: soundService)
let animal = Animal()
let vehicle = Vehicle()

animal.action()
vehicle.action()

Conclusion

I found the 3rd approach to be the most versatile. By using the suggested infrastructure, the consumers gain easy access to the service they are interested in by conforming to a protocol.
I prefer this version because the syntax is concise and easy to remember as it does not alter the original methods of SoundServiceProtocol.
The only caveat is that infrastructure code must be written. The good news is that it only needs to be written once and makes consuming the resulting code much easier.

By using the Swift language features we managed to build a Dependency Injection-like mechanism that makes it easier to handle complex dependencies while keeping the code decoupled.

Where Is It Used

I use this approach on my new iOS game, Hexa Word Search. The goal of the game is to find words in a honeycomb structure.
Give it a try and if you have any feedback let me know.

You can find the entire code sample on GitHub.