In the simulator, select
Hardware → Rotate Left (to get to the Rolling Stones)
Hardware → Rotate Right (to go back to the Beatles)
Hardware → Home (to silence the music)
We will need the notification center to play a video. See Notification Programming. This app is a simple example of how to use the center.
We saw the
device
object
in exercises 6 and 8 of
Hello.
The device object can send out
notification
objects
when its orientation changes (portrait to landscape).
The particular type of notification that it sends out is called a
UIDeviceOrientationDidChangeNotification
.
This is an expensive process,
so we turn it on only when the app is in the foreground.
And the only object in our app that knows when the app is in the foreground
is the application delegate.
By themselves, the notifications sent out by the device do not get very far. But the notification center object would be willing to carry them to objects that are interested in receiving them. Our view controller is one such interested object.
The view controller calls the method
addObserver(_:selector:name:object)
to ask the notification center to carry notifications of type
UIDeviceOrientationDidChangeNotification
from the device object to the
deviceOrientationDidChange
method of its own self
(i.e., of the view controller).
Configuing the notification center is therefore similar to the way we
configured a gesture recognizer in
Swipe:
we specify what method of what object
should be called when something happens.
When each notification arrives,
it is passed as parameter to the
deviceOrientationDidChange
method of the view controller.
We can name this method whatever we want,
but it must take one parameter of type
NSNotification
.
This parameter might carry some useful information in its
userInfo
property,
but our simple
deviceOrientationDidChange
method does not take advantage of this.
It merely
pauses
one
AVAudioPlayer
and starts
playing
another.
The view controller contains an array of two of these players.
deviceOrientationDidChange
also displays a one-line text on the screen.
But this app is not much interested in its visual user interface.
It is intended to demonstrate notification passing.
AppDelegate
.
Generating device orientation notifications is expensive.
Continuous music gets to be annoying.
We turn these features on only when the app enters the foreground.
We turn them off as soon as the app leaves the foreground.
ViewController
View.swift
file.
The view controller’s view is an off-the-shelf
UILabel
.
Beatles.mp3
:
“She Loves You” (1963)
Stones.mp3
:
“(I Can’t Get No) Satisfaction” (1965)
Gone
was our first example of background music.
Find music on
You Tube
and convert it to mp3 format with
http://www.youtube-mp3.org/
.
Drag the mp3 file(s) into the Supporting Files folder in the Xcode
Project Navigator.
Check the “copy items” checkbox.
The view created by this app’s view controller is a white
UILabel
that fills the entire screen.
To tell the view controller to create a view of class
UILabel
,
select the
Main.storyboard
file in the Xcode Project Navigator.
In the left pane of the center panel,
open the View Controller Scene as far as the View in the following list,
and select the View.
▼View Controller Scene
▼View Controller
Top Layout Guide
Bottom Layout Guide
View
In the right panel of Xcode, click on the Identity Inspector icon.
It’s a rectangle with a smaller rectangle in its upper left corner.
When you run the app, make sure the Mac’s sound is turned on.
View
in
View.swift
that is a subclass of class
UIView
.
The view should concentrate on things you can see:
foreground color and
background
color,
width and height,
left justify vs. right justify,
Roman vs. Italic.
AppDelegate
in
AppDelegate.swift
that adopts the
protocol
UIApplicationDelegate
.
The application delegate
should concentrate on the events of the app’s lifecycle:
birth
and
death,
uncover
and
cover,
spring
to life
and
stop moving.
Until now, we have written no code in the application delegate.
But if your app does something that requires
a lot of electricity and processing power,
you can stop doing it in the
stop moving
method and start doing it again in the
spring
to life
method.
See the
endGeneratingDeviceOrientationNotifications
and
beginGeneratingDeviceOrientationNotifications
in the
application
delegate
of this app.
ViewController
in
ViewController.swift
that is a subclass of class
UIViewController
.
For the time being,
all other code
(e.g., opening and playing an audio or video file)
should go in the view controller
by process of elimination.
In the
future
we might have more than one view controller,
or we might have additional objects such as a
model.
But these things haven’t happened yet,
so for the time being please put all miscellaneous code
into the view controller.
In exercise 3 of Hello, we saw that we could get our hands on (i.e., create a variable that refers to) the screen object by saying
let screen: UIScreen = UIScreen.mainScreen();
In exercise 6 of Hello, we got our hands on the device object by saying
let device: UIDevice = UIDevice.currentDevice();
In Gone, we got our hands on the bundle object by saying
let bundle: NSBundle = NSBundle.mainBundle();
Similarly, in any method of any class, we can get our hands on the application object by saying
let application: UIApplication = UIApplication.sharedApplication();
The application object can then be used to get our hands on the application delegate object, which can be used to get our hands on the window object, which can be used to get our hands on the view controller object, which can be used to get our hands on the view object. Of course, we can do this only after all of these objects have been created.
let application: UIApplication = UIApplication.sharedApplication(); let appDelegate: AppDelegate = application.delegate! as AppDelegate; let window: UIWindow = appDelegate.window!; let viewController: ViewController = window.rootViewController! as ViewController; let view: View = viewController.view as View; //We can go even farther down. if view.subviews.count > 0 { //The view has at least one subview. let lastSubview: UIView = view.subviews[view.subviews.count - 1] as UIView; } if view.subviews.count > 1 { //The view has at least two subviews. let nextToLastSubview: UIView = view.subviews[view.subviews.count - 2] as UIView; }
The
init
method of the class
View
in
Button
could have used the first four statements of the above code
to get its hands on the view controller.
But it didn’t need to,
because it received the view controller as a parameter.
UIDeviceBatteryLevelDidChangeNotification
UIDeviceBatteryStateDidChangeNotification
:
unplugged,
charging.
UIDeviceProximityStateDidChangeNotification
:
is it next to a human being’s ear?
MPMoviePlayerController
object can send out a
MPMoviePlayerPlaybackDidFinishNotification
when it reaches the end of a video file.
UIKeyboardWillShowNotification
when the keyboard slides up from the bottom of the window.
There’s also a
UIKeyboardDidHideNotification
.