The app launches itself in landscape orientation. In this orientation, the status bar is hidden because the statusBarHidden property of the UIApplication object is true. The big green View occupies the entire window. It has two white subviews, the paddle and the ball. Drag the paddle up and down.

The CADisplayLink in the ViewController calls the move method of the View every time the hardware refreshes the display. It would be a waste of processing power to call move more frequently than the hardware refreshes the display.

The CADisplayLink can’t be initialized until the view has been created, and the view is created after the init method of the view controller has finished. That’s why we can’t initialize the CADisplayLink in the init method of the view ontroller. Instead, we declare the CADisplayLink to be lazy, which initializes it when it is first mentioned, which happens in viewDidLoad.

Since class View has no drawRect(_:) method (other than the one that does nothing that is inherited from its base class UIView), it is not necessary to call setNeedsDisplay.

Source code in Pong.zip

  1. Class AppDelegate: does the expensive animation only when the app is visible on the screen.
  2. Class ViewController: added the CADisplayLink property, configured by the method viewDidLoad. Added methods supportedInterfaceOrientations and deinit.
  3. Class View: added four properties, the init that takes an NSCoder, and methods bounds, touchesMoved(_:withEvent:), and move.
  4. Info.plist: added the property Initial interface orientation: Landscape (left home button).

Create the project

The CADisplayLink documentation said to import QuartzCore, but ViewController.swift compiled even when I didn’t.

Open the Supporting Files folder and add an Initial interface orientation to Info.plist.

Launch the app in landcape orientation

In Supporting Files in the Project navigator, open Info.plist. Control-click the bottom line and select Add Row. Change the new row to
Initial interface orientation:     String     Landscape (left home button)
See Launching your iPhone Application in Landscape. To tell you the truth, I just control-click on Info.plist in the Project Navigator and select
Open As → Source Code.

Things to try

  1. Make the ball move faster (or slower). In the init method of class View, decrease (or increase) the distances dx and dy.

  2. Uncomment the print in the move method of the View to find the interval in seconds between each refresh of the screen. On the simulator on my Mac, it was 60 times per second (except for the very first interval).
    Open the Macintosh Terminal window and print the reciprocal of the interval.
    bc -l
    1 / (57099.93683947 - 57099.920137308)
    Do the iPhone tech specs give the refresh rate? It was 68 times per second on my Motorola Android phone.

  3. If you want to see the status bar in landscape orientation, add the following method to the view controller.
    	override func prefersStatusBarHidden() -> Bool {
    		return false;

  4. Fix the bug in the logic. A collision is not detected when the ball hits a corner of the paddle.

  5. Play a sound each time the ball bounces off anything. Use this sound technology.