UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Key points

There are two pieces of code I’d like to review before you continue, because both are hugely unappreciated.

First, the assert() function. If you remember, you place calls to assert() in your code whenever you want to say, “I believe X must be the case.” What X is depends on you: “this array will contain 10 items,” or “the user must be logged in,” or “the in-app purchase content was unlocked” are all good examples.

When the assert() line hits, iOS validates that your statement is true. If the array doesn’t contain 10 items, or the in-app purchase wasn’t unlocked, the assertion will fail and your app will crash immediately. Xcode will print the location of the crash – e.g. ViewController.swift line 492 – along with any custom message you attached, such as “The in-app purchase failed to unlock content.”

Obviously crashing your app sounds bad on the surface, but remember: assertions are automatically removed when you build your app in release mode – i.e., for the App Store. This means not only will your app not crash because an assertion failed, but also that those assertions aren’t even checked in the first place – Xcode won’t even run them. This means you can – and should! – add assertions liberally throughout your code, because they have zero performance impact on your finished, shipping app.

Think of assertions as “hard-core mode” for your app: if your app runs perfectly even with assertions in every method, it will definitely work when users get hold of it. And if your assertions do make your app crash while in development, that’s perfect: it means your app’s state wasn’t what you thought, so either your logic is wrong or your assertion was.

The second piece of code to review is the Timer class, which we used like this:

gameTimer = Timer.scheduledTimer(timeInterval: 0.35, target: self, selector: #selector(createEnemy), userInfo: nil, repeats: true)

Timers are rudimentary things, but perfectly fit many games – that code will cause the createEnemy() method to be called approximately every 0.35 seconds until it’s cancelled.

In this case, the gameTimer value was actually a property that belong to the game scene. Cunningly, Timer maintains a strong reference to its target – i.e., it stores it and won’t let it be destroyed while the timer is still active – which means this forms a strong reference cycle. That is, the game scene owns the timer, and the timer owns the game scene, which means neither of them will be ever destroyed unless you manually call invalidate().

In project 17 this isn’t a problem, but we’ll be returning to this theme in project 30 when it is a problem – watch out for it!

By the way: the Timer class really does offer only approximate accuracy, meaning that the createEnemy() method will be called roughly every 0.35 seconds, but it might take 0.4 seconds one time or 0.5 seconds another. In the context of Space Race this isn’t a problem, but remember: iOS wants you to draw at 60 or 120 frames per second, which gives you between 8 and 16 milliseconds to do all your calculation and rendering – a small delay from Timer might cause problems in more advanced games.

The iOS solution to this is called CADisplayLink, and it causes a method of yours to be called every time drawing has just finished, ensuring you always get the maximum allotment of time for your calculations. This isn’t covered in Hacking with Swift, but you’ll find an explanation and code example in this article in my Swift Knowledge Base: How to synchronize code to drawing using CADisplayLink.

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

Sponsor Hacking with Swift and reach the world's largest Swift community!

BUY OUR BOOKS
Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

Average rating: 5.0/5

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.