Stanford – Developing iOS 11 Apps with Swift – 15. Alerts, Notifications, Application Lifecycle

Stanford – Developing iOS 11 Apps with Swift – 15. Alerts, Notifications, Application Lifecycle


[MUSIC] Stanford University.
>>Well, welcome to Stanford CS193P,
fall of 2017 and 18’s Lecture number 15. And
today we have three topics for you, one is Alerts and Action
Sheets. So that’s a way of kind of notifying the user
when an extraordinary event happens, or to help your user
make a branching decision where to go now in the app,
where it’s kind of, you know, two or three choices
of where they can go. The second thing we’re gonna
talk about is Notifications and KVO, that’s a way of
communicating blind and structured inside of our
MVC and then finally, I’m gonna talk about
the Application Lifecycle. We already talked about
the view controller lifecycle, now we’re gonna talk about the
lifetime of your application. All right, so
let’s start with Alerts and Action Sheets. These two
things are very similar, the API to use them is almost
identical, so I always talk about them together. They’re
a little bit different, an alert, it pops up in
the middle of the screen. They’re both modal, they kinda
take over your screen but, alert pops up in the middle. Generally, whatever the alert
is telling you or asking you, you’re only gonna have one or
maybe two choices to respond. It would be unusual to have an
alert, even with three buttons in it. It’s usually for
asynchronous things, things like a network failure
or something that happens out of the ordinary. You don’t
wanna use an alert as just a way to talk to your user and
ask them a yes or no question, things like that. Alerts are
pretty disruptive to the user interface experience because
they lock out the entire app and force you to deal
with this thing. So it’s not a primary, kind of user
interface element, it’s more of an emergency
situation, asynchronous, unusual, that kind of thing.
Now an action sheet is similar in that it’s modal, takes over
the screen, but here you’re almost always gonna have more
than two choices. This thing slides up from the bottom,
you’re gonna usually have two, three, four, five choices,
even. And here what you’re doing is asking the user to
make a branching decision. Maybe they’ve asked
to take a picture, to get a picture in their app,
and you wanna know, do you want it
from the camera or do you want it from
the photo library, or do you want it from
somewhere else? So they’re kind of
branching right there and you can’t really help them
until they make that decision for you, so that’s what an
action sheet is for. It’s not like an alert in that it’s for
unusual circumstances, it’s kind of normal branching
decisions that you would have to make. So here’s what
these things look like, an action sheet slides up
from the bottom like that, and it can have pretty much
any number of buttons although obviously, you wouldn’t want
it to fill the whole screen. And then an alert,
you’ve seen those, they come up in
the middle of the screen, they might even have a little
text field in them as well. So, again, the API for
them, i.e, using them, the code you write is almost
identical, so let’s just talk about one of them first
which is actionSheet. Now, the way both of them work,
they’re just UIViewController. There nothing
special about them, they’re just
UIViewControllers. You know, we learned about how
to present a UIViewController modally in the last lecture,
when we put our emoji art controller document
up modally, it took over the whole
screen until we said done. Same thing here
with alerts and action sheets.
This UIAlertController is a UIViewController and we’re
just gonna present it using exactly the same method we
did to present our document. It’s called present, but we’re
not gonna create it by getting it out the storyboard like
what we did with our document. We’re gonna create it
with this initializer, UIAlertController title
message preferredStyle. And so the title is just the title
you can see on the left there, the image where
the title goes, right? It’s the little thing at the
top Redeploy Cassini, and then the message goes below that
issue commands to Cassini’s guidance system. And then
the preferredStyle is either actionSheet or alert. So,
this is what it looks like for actionSheet. Now, you
create your actionSheet and then you want to add actions,
these actions correspond to the buttons. So, we have four
actions right there in our example in what we’re gonna
control Cassini here, and so we’re gonna have four times
we’re gonna call a addAction. The argument to addAction,
there’s only one argument, it’s a UIAlertAction.
Which is another object and let’s take a look at
the initializer for UIAlertAction. It takes
a title, that’s gonna be the title that appears on the
button, a style, we’ll talk about the styles in a moment
here, and then a handler, and a handler is just a closure
you’re gonna give it. It takes the action as an argument so
that it’s in your right hand, and you’re gonna do whatever
you do when that button gets clicked. So,
this alert in action, sheets have a very simple API,
you just put these buttons and the code that goes
with them on each one. So this handler for, our first
button there, Orbit Saturn, was just kind of a normal
button, so its style is UIAlertActionStyle.default.
And the handler in there, I’m just going to go into
orbit around Saturn. And that’s someone, presumably,
pressed this button once, and Cassini did that,
it’s finished now, but it did that at one point.
So this is just the normal default, action here to
orbit Saturn, right? And I can add another action,
maybe Explore Titan, now, okay that’s not
Cassini’s mission, but maybe we could allow it if we
let, make the person logins. So in the handler there, I’ve
asked them to log in to verify they really want to divert
Cassini to Titan, right? How about the next one, which
is the Closeup of the Sun? Well if I really wanted to
send, this Cassini off to the Sun, that would almost
certainly destroy Cassini. And that’s why it has a little
different style there, which is .destructive, you see where
it says style .destructive? So a .destructive item is gonna
show up in red text right there and it’s any choice
that is going to make us, kind of significant
unrecoverable action happen. you’re gonna delete
something out of a database. For example, That might be a destructive
action, obviously crashing Cassini into the Sun, that
would be a destructive action, so that’s what .destructive
style is there. And then, finally, we have this
cancel action at the bottom, you see it’s kinda
separated a little? And its style is different, .cancel, that’s what it causes
it to be separated. But a very important other thing about
.cancel is that on the iPad, this thing is not gonna slide
up from the bottom. It’s gonna appear in a popover,
which we haven’t talked about, and we’re gonna talk
all about on Wednesday. But a popover is also modal,
kinda takes over the screen, but it appears in a little
window and, in there, you can’t have
a cancel button, cuz a popover is cancelled
by touching somewhere else. A popover comes up,
if you wanna cancel it, you touch somewhere else so
you don’t need a cancel, you don’t wanna cancel button.
That’s why it’s important to note which of your buttons
are a cancel button, so that when this
appears in a popover, the action sheet here won’t
include that cancel buttons. All right, so
we’ve added our four buttons, now we want this thing to
slide up to the bottom and let the user choose and
execute the appropriate handler and we do that
with that same method, present. It’s a ViewController
method, present, presumably the ViewController
behind there, you can see that it’s got the picture of
Cassini. That ViewController is presenting this action
sheet and it’s, you know, present the view controller,
animated true, almost always, and then completion handler
if you want for which will get called when the animation
finishes. So that’s it, super easy to use an alert. Now let’s talk about, this is
an action sheet, by the way. So let’s talk about what it
looks like on iPad, though, I said it was a popover, this
is is what it would look like. In this case, you see that
little redeploy button? And it’s kinda small font, but it says redeploy in
the upper right of the iPad. When I click that, this
action sheet presented well, first of all how do I get
it to present like that? And then second of all,
how do I get it to point to the little redeploy button.
So I have to do both of those things. The first thing I’m
going to do is make it present like a popover. And
to do that, I set the alerts, which is a view control
remember, I set it’s modalPresentationStyle to
be .popover. And that’s gonna make it to represent as
a popover. But that’s not quite enough because I have to
make a point at that little redeploy bar button item.
And the way I do that is I get the alerts popover
presentation controller, which will be nil if you’re
not presenting it as popover. And one of the vars in
a popover presentation controller is the barButton
item that is presenting it. You can also specify
a rectangle, an arbitrary rectangle and the little triangle will point
at that when it appears. You can also specify which
direction the little arrow is allowed to point, left, right,
up or down. And in that way you can control the way
that this popover presents. Does this make sense?
Now you’re probably saying, well I need to put if I’m on
iPad then do this around this, right? Because obviously
on an iPhone I don’t want this thing to be a popover.
But actually, you don’t have to do that, because this exact
same code will still slide up from the bottom on an iPhone.
Now, why does that happen? We’ve specifically asked for
the popover presentation style there and we specified the
barButton item and all that. Well, iOS automatically does
what we called adapting to the environment its in.
Both the trait environment, right, compact width and
or not, and all that stuff we talked about
before, but also the platform its on to some extent.
And so here it notices, well I’m on an iPhone,
I don’t do popovers. Actually, you can do popovers on iPhone
as we’ll talk about, but you have to do extraordinary
things to do that. So in the normal case of events
it doesn’t do popover, so it comes over in
it’s normal way. So if you’re doing a popover, and you have a universal app that
runs on both iPad and iPhone, you’re gonna put this modal
presentation stuff in there. All right, so
let’s talk about alert. Same exact constructor,
you just say preferred style alert, same exact
adding actions. And here I am adding
my cancel button, I’m marking it as .cancel plus
importing in alert because it doesn’t hide the cancel button
in any case cuz alerts look exactly the same on both iPads
and iPhones. And then I’m gonna add another action here
which is my login button. Now, my login button is going
to use that text field, you see that text field? So
how the heck did I get a text field to appear in
the middle of my alert? Well, I just said
alert.addTextField, and the argument to that add
text field is a closure that passes the text
field to you and allows you to configure it.
This is a password for redeploying Cassini off
to the Sun, or titan, or something. So I want it to
have secure text entry, so I’m using the text field var,
there is secure text entry which is part of the text
input traits protocol that text field implements. And you
could do this more than once, you can have more
than one text field. I recommend against that, and
I generally recommend against using an alert as a login
screen. Don’t do that for your final project. If you have a login screen, make it a normal part of your
UI, don’t have it be an alert. But anyway, once you get this
text field added with this and configured, then how do you
get the text out when someone types the text. Well in your
handler of the action for login right there, I’m just
gonna use the var that’s in alert called text field,
it’s an array of all the text fields. I only have one so I’m
going to get the first one and then I’m going to get
the text out of it. Couldn’t be simpler. All right, I almost hesitate
to show you the alert with the text field in there
because it makes you say, that’s a great way to get
text from the user, but again alerts are disruptive so
don’t use them for that. All right, and I’m gonna
present this in exact the same way I presented the action
sheet with the present method, which presents. Just all
present does is it presents a view controller modaly?
And of course this is a modal because the whole screen
is dimmed out, except for this middle box.
All right, and as I said, on the iPad,
alerts look exactly the same. There’s no difference.
So that’s alerts, so let’s put an alert in EmojiArt, just so
we could see this in action. And here’s the alert I’m gonna
put in. Right now, EmojiArt, if you drag any image in
to EmojiArt, it will work. And that’s because I
have that image fetcher, remember that and the image fetcher allows you
to specify a back-up image. And so if I can’t get
the image from the URL with the image fetcher,
no problem, I’ll use the back-up image and
create a one on disk and use that as the URL. Well that solution doesn’t
work too well in iCloud drive. Because I create an EmojiArt
document on my iPad, I drag in something that I
couldn’t get it’s URL so I just put the image locally.
I put it on iCloud Drive, I go over to my iPhone,
I look at it, I can’t see it. Because it’s using the backup
image which is on my iPad. So I’m gonna fix my EmojiArt
just to simply not accept those things. So if you drag
in something that I can’t get its image from the URL, I’m just gonna reject it.
Now I could just quietly reject it. And the user would
probably be like, what’s going on? I keep dragging this and
it won’t take it. But it’d be much better
if I put up an alert and said, I couldn’t get the image
from that URL, sorry, okay so that’s what we’re gonna do.
However, once I got used to that, then I probably don’t
want it coming up every time. Because I do get the feedback
when I drag in a bad image, it just does nothing. And eventually I’ll learn,
that one I can’t drag in, I’ll have to pick
something else. And so I’m going to have my
alert have two buttons. One is keep warning me about
this, and the other one is stop warning me about this.
Those are the only two buttons on my alert. The alert
is otherwise just going to say I couldn’t get the image
from that URL. So that’s what we’re going to
build so let’s go do that. To our emojiArt, here we are.
So here’s emojiArt, if you remember, we do all of
our image dropping down at the bottom here in our draft
interaction delegates here. Right here is
the imageFetcher, here’s what we dropped when we
get the URL, we fetch it with the imageFetcher. But if we
get an image, we use it as a backup image. So we’re
not gonna do this anymore, I’m gonna in fact, stop using
the imageFetcher all together. So I’m just gonna comment that
imageFetcher out. Instead what I’m gonna do is what you
did probably in your homework, hopefully. And
what we did last week in, or the week before,
in the ImageViewController, which I’m just gonna fetch
this thing directly. Now one thing I have to be
careful about here is I don’t wanna block the main queue.
And this closure, the one that load objects, plural, that
I do on a session. This one is a convenience method,
it calls on the main queue. So this closure is on the main
queue doing this. So I do not want that, I want to dispatch
off of the main queue. So I’m gonna do DispatchQueue.global
queue. I’m gonna get do userInitiated, because the
user did just drop this and is presumably asking me
to go do it right now. And I’m going to
asynchronously perform this block. And what I’m gonna do
in this block is go try and fetch that image. So I’m gonna
say, if I can let the image data equal trying to ask
the data to get the contents of this URL, but I’m actually
gonna use the image URL. As you learn in your homework,
sometimes you gotta massage that URL a little bit to get
the right thing out of there. And then I’m going to let
image=UIImage from that data, if I can, imageData.
And if I was successfully able to do all of that, and I’m doing this all
in another thread, so it’s nice I’m not blocking
the UI. Now I can use this URL absolutely normally.
Of course, I wanna now dispatch back to
the main queue. All right? Cuz I’m gonna do UI thing,
which is I’m gonna say, self.emojiArtBackgroundImage=
[url, image]. I’m also gonna do
docself.documentChanged. This is calling the method
that used to be called save. And then after the last
lecture I told you I was going to use delegation to
automatically track changes. Well this is one
of the changes I have to track. If you change
the background image, I have to let the document
know that it has changed. And we’re going to look at
document change in a little bit later demo, today.
It’s exactly the same as save, I just renamed it
document change. But we definitely want to do that
in here. Now, here’s the rub. Here’s the alert magic.
If I couldn’t do that, if I was unable to get that
image out of there. Now I wanna put up an alert instead
of using that backup image. So I’m going to say here,
self.presentBadURLWarning, and I’m going to actually
pass the url along. Now why am I passing
that url along? I’m not gonna do this for time
reasons, but you know what would be a really cool thing
is someone drags something in, it puts up the alert. They’re
like, don’t warn me again. And they say stop. But then
they drag another one in and it doesn’t work. Then they
try a different one and it doesn’t work. And they’re
like, it’s broken. They’ve kind of forgotten that they
said stop warning me that. So somehow you might
want that alert to come back on. At some point, right?
And what would be a cool way to do that? How about if they
drag the same url in twice. Because that’s them saying,
drag it in. It didn’t work. Why didn’t it work? Let me try
again. Well if they’re trying again they probably
forgot about that alert. Maybe, maybe not,
but it’s likely. So that’s the kinda thing
you can do in your UI that’s a little tricky, that allows
them to turn things like that back on without having to go
to settings somewhere and turn it on,
which is really cumbersome. It’s just kind of using their
natural things that they’re doing. In the UI, you can
make decisions like this. So I just kinda want to give
you just kind of a classic Does that make sense? example of that. So that’s
why I might pass this URL on, because I might want to check
to see if it’s the same URL. Now I’m not gonna do that
today, for time constraints. But I just wanted to give you
the idea you could do that. All right, so let’s do
our private func here, presentBadURLWarning for URL. And what am I
gonna do in here? I’m gonna create that
alert and present it. That’s why we’re here,
is to learn about alerts. So creating alert is just
creating that view controller. So let alert=
UIAlertController. Why they didn’t call it
UIAlertViewController, I do not know. They did not.
So UIAlertController, and the constructor for it here,
we always want this one down here. You can see this
one’s that NS coder stuff we learned about before. This is
is kind of an old style thing. We always want this one right
here, that gives us the title, the message that’s
gonna go in there. And the style, whether it’s an
action sheet or an alert. And so our title here,
what’s happening? Well, they dropped an image.
We couldn’t get the data. So I’m gonna call this thing
Image Transfer Failed, maybe. It’s actually very important
to pick good phraseology here, cuz you don’t wanna freak
your user out. My gosh, what did I do or whatever?
You wanna try and give them something that
gives them the authority, kind of project some authority
that this, don’t worry, this happened. I understand
it and here’s your options. But not something that’s so
technical that they’re like, what? Like if we say something
like couldn’t load from URL. Okay well users don’t even
know what URLs are. So you wouldn’t wanna
put URL in here. You see what I’m saying? So image transfer, when they’re
dragging presumably they’re trying to transfer that image.
You know, it’s a good name. Maybe we might even wanna say,
image drop failed, possibly. You know, this is the kind
of thing you user test and you try and get the right
words. Of course, the other thing here is
we wanna localize this. And I’m gonna talk, hopefully
the week after Thanksgiving, about how to localize your app
for other languages. Because we want our app to run in as
many languages as possible, so we have to make that string
be able to be localizable. And it’s quite easy to do in
iOS, but we’ll learn about that in a couple weeks. And
now here’s the message where I’m gonna tell them more
about what happened. So here I’m kind of saying
what happened here, which is that I couldn’t transfer the
dropped image from its source. Again, I’m not mentioning
the term URL or anything like that.
I’m just doing that. And of course this is an alert,
not an action sheet, so we’ll say that. So this
creates this view controller, and then I’m just going to
present I am a view controller here, present. So I can
call this method on myself, it’s a view controller method,
present. I’m gonna present the alert,
animated true, and I don’t have any completion
thing I wanna do so I’ll just leave that off. But of course
I need to add my buttons here. So what buttons
are we gonna have? Well, remember I’m gonna have
keep warning me and stop warning me. Okay so, let’s do
the keep warning one first. So I’m just gonna say
alert.addAction and remember the action you can
see takes us one argument, which is a UIAlertAction. And
that has only one initializer, which is these one right here.
So make it so you can see even better here.
All right, so it wants the title. That’s
the title of the button. So this is the one where I’m
going to keep warning the person. And the style for
this is just default, this is the normal default
button. Keep Warning isn’t anything special, it’s not
gonna change anything, really. We just keep on warning them. And I actually don’t
need a handler here, cuz I’m not gonna do anything, if you keep saying
Keep Warning me, cuz that’s what
I do by default. So I’m just gonna get rid of
that, and that’s my action. So a lot of time cancel
buttons and okay buttons, they don’t have any action,
they don’t do anything. And that’s, this is kind of like
an okay button in a way. But our other button alert add
action, UIAlertAction. This one does have a handler,
and let’s talk about how we’re
going to implement this. Let’s see, now it’s on one
page there. So here this, this string is Stop Warning. Now if
I just have Stop Warning and Keep Warning, that’s really
not enough information for people to understand. What do you mean Stop Warning?
You know what I mean? So I actually wanna add a little
more to my message up here. I’m gonna say something
along the lines of, show this warning
in the future? Now, Keep Warning and Stop
Warning make a lot more sense. However, you don’t
want this to be yes and no. Having buttons in
an alert, yes and no. That forces the person
to go carefully read and parse the message you said.
And they don’t get any double check that they read it right
before they press yes or no. So always try to pick things
that are more descriptive than yes or no, like keep this
warning, stop this warning. Okay you still
have to be brief, you don’t want these buttons
to have ten words on them. So it’s a compromise
between brevity and making sure the person
understands. Now I’m gonna call this
destructive because it’s going to stop it doing something
that it does pretty much permanently unless I go
add that feature where I compare the URLs and turn it
back on. So I’m gonna set this to destructive. So it’s gonna
turn out red. It’s gonna make the user think a little
bit before they press that, which is exactly what I want.
And how about our handler here. So the handler passes
this action back to us. And we usually don’t
need that because we can just capture it in
using closure capture, we capture this little action.
Although, you know, since you usually add it like this, you
don’t actually have a local var to this action. So it’s
kinda nice that it passes it. We don’t need it in any case.
All we need to do here is set some var that says,
suppress these warnings. So I’m gonna say self.
suppressBadURLWarnings=true, so I need a var for this.
So I’ll put that up here, private var, I think I copy
and pasted it, yeah I did. Equals, of course it’s
gonna start out false, we’re not gonna suppress it. And all I’m gonna do is, not
do this method if that’s true, so I’m gonna say if
suppressBadURLWarnings, not then do this. So that’s it, that’s the entire
implementation of this, let’s go see this working.
Here’s our app right here, let’s open up our Apple Bees
document right here. Here it is, and let’s try dragging
in an image, that works. How about I think this one
works, this one has an URL. So we drag it in, it loads
it up, excellent, it worked, it’s got a high resolution
image, that’s good. How about let’s drag in
one that doesn’t work, how about this one? This one
happens to not have a good URL, all right,
we got an alert here. Couldn’t transfer the dropped
image from the source, show this warning in the
future, keep the warning, or stop warning, so I will
keep warning. That’s good, let’s try another one,
how about this one down here? That’s also no good, now I’m
tired of this warning, so I’m gonna say, stop warning
me. Now let’s try and drag this bad one in
again right here, no warning. All right,
so that’s that, let’s get back to our slides,
and action sheet is exactly
the same, right? You’re gonna do exactly
the same thing over there. All right, our next topic here
is notifications and KVO. So if you remember back to
the MVC talk I did at the very beginning, like, second
lecture. I had this little radio station, the little
orange things right there. I said, well, the model can’t
talk to its controller, so it has to use other mechanisms.
And why can’t the model talk to the controller? Because the
model is UI independent and the component is
fundamentally UI dependent. So there’s no way for them
to talk in that direction. The controller can talk to the
model, but not the other way, so we have this blind and
structured way of doing it. By the way, a view might
also want to use this radio station to talk to its
controller because the view can’t also talk to
its controller for a different reason. The view
is generic, and the controller is specific UI. So there’s
no way generic items like buttons could know anything
about a particular controller. So for both reasons, the
viewing model ca’t talk to the controller, controller
talking to them is okay, but ca’t do the other way. So they both could use this radio
station model. And there’s really two ways to do radio
stations, notifications and KVO, KVO stands for
key value observing. So we’re gonna talk about this
radio station, by the way, only I call it radio station,
it’s not called radio station in the doc. But a radio
station is a good analogy for the kind of communication
that’s going on between these things. All right, here’s
notifications, the first of these. So a notification
is essentially just a way you’re gonna register
a closure to get called when someone broadcasts on a named
radio station. That’s all it is, very simple, you can see
how it’s immediately blind. Nobody knows who’s
any classes, all we’re talking about here
is this radio station. And it’s very flexible, cuz you just plop a closure
down there, and it just calls it when someone broadcasts
on that radio station. And it’s also possible to
broadcast music on a radio station. In other words,
when you broadcast, you can put information across
the radio station as well, which is kinda cool. All right, so this is what
the function to say I wanna listen to a radio
station looks like, this code you see up right here.
All of this stuff is done via this thing right here,
NotificationCenter.default. You see that
NotificationCenter.default, and I’m using it down here. So
NotificationCenter is a thing that you use to both sign up
to listen to a radio station, and to broadcast on
a radio station. And we always just use this
default shared instance of it, kind of like user default,
remember that one? We had userdefault.standard,
we just used the shared one, same thing here. So this method to say you wanna
listen is called addObserver. You’re essentially going to
observe this radio station, to listen to see if
anything is broadcast there. And you see it has
a return value there, which is of type NSObjectProtocol, I’m
gonna cover that in a second. But first let’s look at
the arguments to this thing. First of all, we have forName,
you see this, right, forName, Notification.Name, that’s the
name of the radio station. And notice it’s type
is not string, it’s Notification.Name. And
so if you, when you name it, you will have to create your
own Notification.Name if you wanna broadcast on your own
radio station. Which is fine, you wanna give your radio
station a unique name. But if you wanna look and find
the radio stations that exist already in iOS, and there are
dozens of them. iOS is very good at broadcasting on
a lot of radio stations. You can just go look in
the documentation for Notification.Name, and you’ll
see them all listed there. What they do, when they
broadcast, that kind of stuff. So that’s why it’s nice that
they made it not a string, but a type that you can go
look up in the documentation. All right, the next thing
is this object Any?. That is who’s broadcasting
on this radio station, because unlike real
radio stations, multiple people can broadcast
on the same frequency, and that’s perfectly allowed.
And this just says who is broadcasting at the, who
did the broadcast that you’re receiving when your closure
gets called here. And then you see right there,
we have the queue, this OperationQueue. That’s
what queue do you want your closure to be executed on.
Now, this can be nil, but you almost never want nil.
What nil means is, execute my closure on the same
queue as the broadcaster. You do not want that usually,
unless you’re the broadcaster, if it’s your own code, and
you’re doing the broadcasting, maybe you want that. But if you’re listening to
something from iOS, for example, no, you probably
want the main queue. Now, notice that says operation
queue, not dispatch queue, and I actually mentioned this when
I talked about dispatch queue. That there’s an object
oriented API to doing all that dispatch stuff, called
Operation and OperationQueue. Well, this is using that
object-oriented API, if you want the main queue, which is what you
want 99% of the time, just say OperationQueue.main.
The same way you say DispatchQueue.main, you can
say OperationQueue.main. And then the last argument to this
addObserver is the closure you want to execute. And that
closure only has one argument, which is a notification. A
notification is just a little object that has, for example,
the name of the radio station and who the broadcaster is.
But it also has a very important piece of
information called userInfo. userInfo is the music that’s
being broadcast to you, it’s almost always, it’s a type any, but it’s
almost always a dictionary. And when you look in
the documentation notification name to find all
the radio stations. They will say,
when we broadcast, we include the following
keys in the dictionary, this information. So that’s a very
important piece to understand, is that your closure has this
one argument, notification. You look at the var userInfo
in that notification to get the music that’s coming across
the radio station right now, all right? Now let’s talk
about that return value, you see that
observer up there? Notice that really weird type,
NSObjectProtocol, what the heck is
NSObjectProtocol? NSObjectProtocol is a protocol
that NSObject happens to implement. It’s a subset of
the functionality of NSObject that some objects implement
that aren’t subclasses of NSObject. So that, you know,
this kind, this well-known set of things. However, that’s
completely irrelevant here. Does not matter. That thing
might as well be in any as far as you’re concerned. All this
thing, this observer thing is a cookie that just keeps
track, that basically this observation is this thing.
So, it’s just a cookie for you to hold on to.
You only do one thing with it, which is stop observing.
It’s how you say I don’t wanna listen to that
radio station anymore. And you do that by asking the
NotificationCenter.default to remove observer, this cookie.
And it will stop listening. So we’ll show you an example
of that in a second. Quickly on Notification.Name,
all of the notification names, they collect them as static
lets, little static let constant Notification.Names in
the Notification.Name class. By the way, you’ll often see
it called NSNotification.Name. That’s the same thing. They’re literally type aliased
to each other. You know, in the Swift world, we would
call it Notification.Name, and in the Objective-C world,
NSNotification.Name. Fine, they’re the same exact
thing. And again, if you wanna create your own radio station,
we actually, or I recommend creating an extension to
Notification.Name, and adding your own static let
which is your thing, equals, Notification.Name, of some
string, any string you want. That way you’ll be collected
in exactly the same kind of API realm as all of
the other notification names. And you’ll see that when we
do the demo. All right, so here’s an example of listening
to the radio station. What’s a good example? This is a great example.
Remember, the slider that said, set your
font size, the accessibility slider? You can make it bigger
and smaller? Well, you can find out, because there’s
a radio station broadcast anytime that changes. So
that’s a great thing to know. If you have something in your
UI whose font is based on that, for example, we talked
about doing the cool thing of having the collection view
on the top of emoji art, having its emoji get bigger or
smaller, based on this slider. Which would not be that
hard to do. I’m not gonna do it as a demo but
you can do it as an exercise. The main thing we would have
to do is have our cell size be, fixed to this font
size by doing our little font metric scaling.
And we would also have to have a layout constraint for the
height of our collection view that we wanna set in code to
be the height of the cells. Because remember that our
cells can’t be larger than our collection view. So we’d have
to make the collection view bigger and the cells.
But we could easily do that. But if we did that,
we would definitely want to be listening to this
radio station. Because every time
that font changed, we’d have to re-layout our
collection view, of course, all right? So here’s
what it would look like. We get the
NotificationCenter.default. We create this observer var
which we set equal to doing addObserver. The name of
that radio station is Notification.Name.UIContentSi-
zeCategoryDidChange. That’s kind of a mouthful but
that’s what it is. We’re listening for that
from UIApplication.shared. That’s the application object.
I’m gonna talk about that at the end of this lecture.
You could also put nil there. Cuz basically if anyone
broadcasts that thing changed, you’re interested. So it would
be fine to say nil here. That means if anybody
broadcasts it. And then of course OperationQueue.main. I
say or nil but really we would want .main there. Cuz we’re
not actually sure what thread this iOS would be
broadcasting this on. So we want to make sure we’re
on the main thread when we do our stuff, and then our
closure. Now inside our closure we cause our
collection view to redraw. Whatever we do is fine.
And also notice there, there’s something, some music
broadcast on this station. Which is, you can find out the
content size category. And so there’s names for
all those detentes, in the slider there, like
UIContentSizeCategorySmall, UIContentSizeLarge,
UIContentSizeCategoryAccessib- ilityLarge, which
is even larger. And there’s like very large,
and extra large, I don’t know. There’s all kinds of different
spots in there that you could look at if you wanted to. But
you’re probably not going to. You’re probably in that
collection example just going to resize your font based
on the font metrics. Remember how we do that scaled
font thing off the UI Metrics. You would just cause that to
recalculate, all right? Now, notice that I hold on to var
observer right there. And then I remove it when I’m done. So,
it is a good question here. When do I add and when do I
remove observing. Well, almost always you’re doing this as
part of something you’re doing in the ViewController.
So a perfect time and probably 90% of the time,
when you get viewWillAppear or viewDidAppear, you
add observer. And then on viewWillDisappear or
viewDidDisappear, you remove the observer.
That makes sense? Because you’re only interested
in really getting these size changes while
you’re on-screen. of course, the size might
change while you’re offscreen. Now if you do that, So when you get
viewWillAppear, you’ll probably also wanna
look at the size category, which you can do.
UIApplication has a var for that. And adjust your
collection view then before you appear. But
it’s kinda a waste for you to be listening to that thing all
the time and changing things when you’re not even on
screen. So viewWillAppear, viewDidDisappear are great
places to put add observer, remove observer pairs. Always
pair these things. Don’t forget to remove observer. How
about broadcasting on your own radio station. How do you
do that? You do that with the NotificationCenter.default
as well. The method there is called
post. The first argument, the name, is the name
of the radio station. You get to make that up. We’ve
talked about how to do that. object, that’s you. That’s
who’s sending it. Usually that’s self. You can make that
any object that you want. But, that is who
the NotificationCenter will report as the sender, the broadcaster.
And then userInfo, that’s your music. And that’s, almost
always, you’re gonna want to put that as a dictionary
of AnyHashable thing to an Anys. So it’s very
flexible, you can put anything you want in there. Now, as
soon as you call this method, it will immediately call
all the closures for that have addObserver
to your radio station, with a following caveat.
It’s only gonna immediately call them If they
specified queue nil. Cuz then it’s gonna execute
their closures on the same queue as this. So
then it executes right away. If they specified a different
queue like the main queue, then this is going to post
their closures to execute. And it will execute
as soon as that queue gets around
to their closure. So that’s notifications.
All right, KVO. Now I’m gonna spend two slides on this. But
I wanna emphasize up front, this is not a major important
thing you’re gonna do this. Most quarters, I don’t
even talk about this. But I kinda decided to throw
it in this quarter just so you can kinda know
it exists out there. It’s not really a primary
way of doing things. Notification is much
more of a primary way. This much less primary.
And it’s because, it’s because it’s kinda limited a little
bit in its application. So what is KVO? The basic idea
here is, when it comes right down to it, it’s the idea of
registering a closure that gets executed when a property
on a sub-class of NSObject changes.
That’s pretty much what it is. Now let’s talk about some of
the caveats I just put there. To make KVO work, you can’t
just have any property and you change it and someone
can register a closure. Think about the overhead
of doing that. You would not want that for
every property. A lot of properties are
probably they act as inlined by the compiler. So there’s no way you would
be able to do that. So there’s a mechanism that’s
required to do this. Now NSObject, remember
what NSObject is, right? It’s the root of all
iOS classes, right? So UIViewController, UIView, they
all inherit from NSObject. So NSObject puts
this mechanism that makes it possibly to
watch a property into it. So that’s why I say This is
for subclasses of NSObject, you could put this mechanism
in your own object, however. It’s not that difficult,
I’m not gonna cover it, but people usually don’t.
They just use the mechanism of using NSObject by having
their thing, whatever it is, their class,
subclass from NSObject. So that’s the first
thing to understand. There’s kind of some mechanism
there that you would have to implement if you didn’t
wanna subclass NSObject. What is this thing good for,
what’s KVO good for? Well, it’s kind of good for some the
same things as notification. Blind structured
communication between things, especially between models and
their controllers. But also between a view and
their controller, or even between a view and
itself, as you’ll see in the demo here. Not every
property works with KVO, as I said,
that would be ridiculous. For a property to work with it, not only do you need
the NSObject mechanism, but the property has to be what’s
called key value coding compliant. Now,
what that means is, that property can be set
by sending set value for key, where the key is the key
path of that property, and get value for key to get it.
In other words, there’s these functions, set
value for key and value for key, that you can call to get
the value of the property. That has to be possible
on the object, that has to work if
you want do it. And that’s called key value
compoding, key value coding compliant. So that property
has to be that way, now, you have to do some work to
make that happen. Properties don’t just magically make that
work, you usually have to implement something like value
for key and set value for key to make that work. Now,
there are a few properties scattered throughout iOS that
are key value observing, that work with key value
observing. Most notably, in UI view, center and
frame are key value observing. So you can observe the center
or frame, and/or frame of a view, and you can find
out when it moves, so that’s kinda cool. Also,
most of the properties in the CALayer underneath UIView,
remember the place where we put the border
around the view, back in assignment three or
something like that? That layer that’s doing a lot
of the drawing for UIView, that layer is mostly key value
observing compliant. So you can observe things happening
at that layer as well. And they are scattering other
places, for example, core data. Remember core data,
the object oriented database? Key value observing can
be really big there. You could watch everything
happening in your database on a per-property basis by
using key value observing. So there are some frameworks that
actually use KVO a lot. But for the most part,
we don’t use it in the main line that much. And of course,
you could make your own NSObject subclass that
implements this stuff. But that’s way outside
the scope of this class, and again, template sizing is not,
this is not that huge a deal. All right, so how does that
work, what is KVO look like? There’s this one very
important method that NSObject provides for you,
called observe. So observe takes a keyPath as
an argument and a closure, and it executes that closure
whenever that keyPath changes. Only works for keyPath that
are key value compliant, key value coding compliant.
Notice that it returns a little cookie,
our observation, you see that? It’s a little
different than a notification, though, you never say, remove
observer on that cookie. Instead, when that cookie
goes out of the heap, it stops observing.
So as long as you want this observation closure to
be observing that thing, just keep that cookie in the
heap. As soon as you let it go out of the heap,
it will stop observing. Now, the arguments you see to
your closure, of course, you get the thing that’s being
observed, observed handed back to you. You also get
this thing change, that change is of type
NSKeyValueObservedChange. And that’s a little object that
you can get the old value of the thing, the new value
of the thing that changed, that kind of stuff. It just
basically tells you about the change that happened, that caused your
closure to get called. This KeyPath argument is not a
string, used to be in the old days. Nowadays, it’s actually
a typed thing in Swift, and it has special syntax, which
is backslash, the type, dot, the name of the property. Now,
Swift will infer the type for you, so we almost always say
backslash dot the property. So for example, if we want
to observe the center or frame of a view we would
say observe .frame. and that will be observing
the view’s frame. All right, so I have a demo of
both of these things, notifications and KVO, so
let’s take a look at these. What I’m gonna do here is,
remember after last lecture, I said, we don’t want to have
a save button in EmojiArt. We’re gonna get rid of that, there’s no reason to have
a save button. Really, when we hit Save, we were
just telling our UI document, something changed, so
you should autosave soon. Really, what we want is to
watch our EmojiArt view, and whenever an emoji
gets added or resized or moved, we want to
notify the controller. So the controller can tell its
document, something changed, then we can just ditch
the save button. Well, after lecture last time, I told you I was gonna
do that, and I did. So the stuff that’s posted has
this in there, and what I used was delegation. And it did it
specifically cuz I wanted you to see what it looks like
to make your own delegate. You’ve been using
scroll view’s delegate, table view’s delegate,
collective view’s delegate. I wanted you to see, wanted
you to make your own delegate, so I created
an EmojiArtViewDelegate, and I’ll briefly show you
what I did there. And so that’s great, but
today, what I’m gonna do is use notifications instead.
Because you can image, anything that’s happening
with a delegate, that’s blind structure
communication. Well, we can do that with a notification just
by having a radio station, which is the EmojiArt view
something changed radio station. And a controller will
just tune in, and every time it hears a broadcast on that,
it’ll tell its UI document, something changed, that’s what
I heard on the radio station. And so that’s what we’ll
do there, and then KVO, there’s a great
use of KVO here. Which is, right now, I had to
go down where my gestures are, remember, I dragged in some
gesture code. I had to go in there, and for every time
a gesture changed the position of an emoji, I had to tell my
delegate something changed, tell me. So I had a lot of
code in there for that, so I’m just gonna rip
all that code out. And instead, I’m gonna observe
the center of my emojis, and when my emojis move, or
even when they’re resized, because when they resize,
they have to be repositioned, right? Cuz they grow from
the upper left corner, so I have to keep
repositioning, so I’m setting the center again.
So I’m just gonna observe that,
and when that happens, then I’ll broadcast on
my radio station. So that’ll collect that code into
one place, and keep it from being spread out through all
over my code in a messy way. But before we do that stuff,
I’m going to do a simple notification thing, which is
I’m just going to observe the state of my UI document
changing. You know how our UI document goes through these
document states, normal, closed, progress available
when it’s, say, reading and writing, saving, error,
remember all those states? Well, we’re gonna watch that
happen, just to kinda get a warm up on notifications, to
see what that looks like. So let’s do that one,
I’m gonna go up here, here’s viewWillAppear, right
here, and close. Right, so here’s our document opening
and closing up here. So all I’m gonna do here is, when
my document first appears, I’m going to start watching my
document. And it broadcasts on a radio station that tells
me when its state changed. So what does that look like,
well, again, i need to capture
the return values. So, i’m gonna call my
documentObserver equals, let’s go ahead and
make a var for that. private var documentObserver,
remember, it’s an NSObjectProtocol, optional.
Again, this is the cookie, we never send a message
to this, ever. We don’t even not know what messages it
responds to. So we’re gonna, create this document
observer here, I’m gonna do NotificationCenter.default
That’s how we do all of our stuff. And do addObserver, so
here’s addObserver forName, make this a little
easier to read, is what I want to do here.
I wish they had a little command key I could
do that would do this for me. All right, so we’re gonna
listen to the document state radio station. So we,
let’s find the name of it. I’m just gonna type,
Notification.Name., and you’re gonna see how many
radio stations there are in iOS. A lot, okay? And you
can go look at all these and what they broadcast and what
music they play and all these things. We’ve already talked
about some of these things, for example, keyboard. Here’s
a keyboard hide, DidHide, will show. And then of course
the content category size did change thing, right?
There’s that there. So, the one we want is
UIDocumentStateChanged, you see the first one there?
So UIDocumentStateChanged, so that’s the radio station
we want to listen to. We’re only interested in
broadcast from our document. That’s the sender. That’s
who we want to broadcast. We of course want to be on
the main queue here. And here’s the closure that’s
gonna be executed when someone broadcasts on that.
Here’s our notification. Now this notification I think it
actually does have some music on there, which is probably
the document state. But I don’t even need it cuz I’ve
got my document right here. So I’ll just grab its state.
I’m just gonna say print.documentState changed
to. And we’ll say are
self.documentState. I actually added a little extension to
documentState right there so that it would print it
out nicely .normal.close, those kind of things. Now
anytime you start listening on a radio station, you
immediately have to think when am I going to stop listening
on this radio station? Well, here I’m starting even
before my document opens, but I’m waiting until view will
appear. So I’m going to stop, I could stop in view
will disappear or view did disappear, but I’m actually going to stop
when my document is fully closed.
Once it’s fully closed, I certainly don’t want to
be watching it anymore. So let’s go down here where we
close. This is the close, here is where we closing.
Right now we don’t use the little success closure
that happens when we close. But I’m going to star using
it. Success in space, Return. And in here I’m
going to remove observing this documentObserver.
So I’m just going to say here, if I can let observer, server
equal my documentObserver. Then I’m going to ask
the NotificationCenter.default center to remove
that observer. In other words, stop observing
that. Everybody cool with that? Everyone understand
what I’m saying here, about this is the completion closer
from closing the document? So once it’s closed, that way
we’ll be able to observe it closing. It will be nice.
So let’s go run this and watch our console, so I got
my console going down here. Actually, this is my console
over here. All right, so let’s run. All right, so
here’s our app. So we haven’t opened any documents.
So we have nothing on here. I’m gonna go ahead and
clear out my console. So we haven’t opened
any documents. So we haven’t gotten any
documents to exchange. So I’m gonna open our Apple
Bees. Here is our Apple Bee. And look, documentState date
changed to normal, right? Because we opened
the document, now it’s in normal. Now,
how about putting something in here maybe an apple, something
like that. Now it’s, where, what’s going to happen to the
state right now? Okay well, eventually it’s going to
autosave. It does it about, I don’t know, once a minute or
something like that. But when it autosaves, we’re going
to notice because it’s going to go to state progress
available. There it is, progress available and
then back to normal. Because the progress is available
because it’s saving and it can tell you the progress
as it saves, and then goes back to normal. I’ll
show you another trick. Here, you can force an autosave,
by the way, by threatening to switch to another app.
Watch this, I’m going to drag up from the bottom like, I’m
gonna switch to another app. This caused an autosave. Now,
it didn’t do it here because we haven’t made any changes.
But this is a great way to make sure that you’re
changing stuff works. So watch this, now I’m
gonna add a something here. Now when I do this threat,
whoop, it’s saved. See what happened
there? So when you threaten to switch to another app
autosave will auto save. Cuz it’s just afraid, my gosh,
I might get killed or who knows what,
I better save. So that’s a nice trick to
know when to do that. And if we close this then we get
state changed to closed. So this is cool. We just listened
to that radio station, we’re just reporting
what happened. All right,
now let’s go ahead and have our emoji artview
be a broadcaster. We are listening to UIDocument
which is the broadcaster here and we are the subscriber
to the radio station. Now let’s go the other way,
let’s have a broadcast. So I’m gonna go over to
EmojiArt, and what I’m gonna do is every where I was
doing my delegation, I’m going to use notification
instead. So let’s first review what I did after last lecture
to implement delegation. All right, now, just like
UIScrollView, UITableView, etc, I had to add
a protocol for delegation. Now my delegation
protocol it’s called EmojiArtViewDelegate only has
one function in it which is emojiArtViewChanged. Of course
ScrollView has a whole bunch of them. DidScroll, view for
zooming at, table views delegate has a lot of things.
Height of row at, all these other things. We only have
one, just this one. Now notice I made this restricted to only
being implemented by classes. Why did I do that? Because
the delegate method, or var, the delegate var in my view, I
wanted it to be weak. And for it to be weak, it has to
be able to be in the heap, and then get released and set to nil, when no one else
is interested in it. Why did I make that weak? Well, imagine
here that my controller sets itself as the delegate, which
is likely. Very, very likely. If that happened,
now we’d have a memory cycle because my view would be
pointing to the controller. And of course, the controller
points to all of its view. So now they are pointing
to each other. They are going to keep
each other in the heap. By making this delegate weak,
it makes so that’s no longer
going to happen. So there’s not a memory cycle
because the view is not keeping the controller in
memory cuz this is a weak pointer to it. So I added
this var, this weak var, so now anybody who wants to know
if I’ve changed can just set themselves as the delegate and
of course the controller is going to do that. Then, every
time I changed like right down here. I just sent this message
to my delegate if I have one. My delegate could be nil, I
don’t have to have a delegate. And I just send it and of course I’m the sender,
right? Delegate methods, we all will send ourselves along
as the first argument. Do you know? You’ve noticed that
I’m sure with ScrollView and TabelView and collection.
They always send themselves, it’s just convenience sake so
that you have it right there. So I do that as well. Now
this is not the only change, this is one I’m dropping.
Of course, if I drop a new emoji in, that’s a change, but
I also had to go over here to gestures. And this is what
I was talking about before, it’s kind of annoying like when I select and move
a view. I had to say, well, if this is the end of this
gesture then send it. And also down here where I
resized. I had to go and say, well, if it’s the end
of resizing, send it. Now I want to get
rid of these and I’m going to be able to with
KVO, but we’ll leave them in there for now. So that’s
delegation. That’s all that’s necessary on this view side.
Then on the controller side, what I did was when I created
my emojiArtView down here, I set myself as its delegate. Well, if I’m gonna
be its delegate, that means I have to implement
the EmojiArtViewDelegate just like those implementing
scrollviews delegate. And that means I have to
actually implement that which is right here in my
emojiArtViewDelegate methods implemented, and what did I
do? I called documentChanged, and what is document changed?
Here is document changed, it’s the method
formerly known as Save. Cuz I ditched my Save
button when I did this and just called and Save. These
contents up here is exactly the same as it used to be.
Just update my documents model to be my model and then
update the documents changed count. It’s all I do here.
So that’s delegation, that’s the entirety of it.
You see how it all works? Quite simple, and
we’re not gonna, we’re not use delegation
anymore in this. We’re gonna leave
delegation in the view but we’re not gonna use
it in our controller. Instead, we’re gonna
use a radio station. So let’s go back
to our artview and broadcast on a radio station.
And I’m just gonna do it everywhere where I was
talking to my delegate. Instead, I’m gonna broadcast
on a radio station. I’m just gonna say
NotificationCenter.default.p- ost, that’s how we broadcast. And I have to give it a name
and who is broadcasting. Well, who is broadcasting is me,
and what are we gonna do for a name? Well, as I suggested,
I recommend going here and doing an extension to
notification.name and add your own static let
which I’ll call EmojiArtView did change notification and
set it equal to a notification.name with any
string you want in here. I’ll probably just use
the same string here. It doesn’t have to be the same
string but I will, and this will now make it so you can do
notification.name.emojiartvie- wdidchange. That’s the name
of our radio station. Remember radio stations
are Notification.Names, so this is that. So now,
I can go down here and say I want my name to be
Notification.Name.EmojiArtVie- wDidChange. And by the way, of
course, Swift can infer this. So we can just go like that,
which is what we would do, and type all of that in
Notification.Name stuff for no good reason. And this is
it, so that’s all we need to do is do this. Now of course,
we need to do it here, but we have to go again
over to gestures over here. And do it in the same place we
do this delegate right here,, where’s this other
one up here? Okay so, again,
that’s kind of annoying, we’ll fix that with KVO. But
right now, we’re broadcasting on this radio station every
time something changes. We resize something, we drop
something, and whatever. Now, back over here
in our controller, I’m no longer going
to be a delegate. So I’m gonna go down here and
just get rid of all this. So I’m not longer gonna set
myself as the delegate here. Get rid of this entirely,
I’m no longer gonna implement the EmojiArtView delegate. I’m
no longer going to say that I implement
the EmojiartView delegate. So, now I’ve disconnected
myself from my view. So instead, I’m gonna listen
to that radio station, so where am I gonna do that? That
one, let’s start listening once the document’s open.
Until the document’s open it’s gonna be useless to listen to
my emojiArtview. So again, I’m gonna need another
little observer guy here. So I’m gonna call this one
my emojiArtviewObserver cuz that’s what its gonna be
observing, the emojiArtview. I’m gonna say
emojiArtViewObserver, go, ‘m inside a closure here, cuz
this is the completion closure of opening. So I’m gonna say
self.emojiArtViewObserver =NotificationCenter,
that’s how we listen. Default.addObserver, same
way as we add observer for the UIDocumentState.
Let’s sort this out again, so we can see this all real
clearly. All right, so the name is
notification.Name.EmojiArtVie- wDidChange. And again,
we don’t need that just I was doing that so we would see
it clearly. The object is my EmojiArtView, that’s the only
one I’m interested in hearing about emojiArt,
you did change broadcast. The Queue, of course operation
Queue.Mean because I’m just, although surprisingly this
would not need to be on main. Because all I’m gonna
do is tell my document, which is part of my model,
extended part of my model. I’m just gonna tell that it
changed. That’s not anything UI, so I don’t necessarily
have to do that here. I could put nil here and be pretty
safe no matter what thread I’m broadcasting on. Now I happen
to know that my emojiArtView is broadcasting from the main
thread, right? Because it did it when it dropped or
when someone resized, clearly, I’m on the main queue there.
So it wouldn’t matter but, anyway. Okay so here we go, now we do get this
notification. Turns out that our EmojiArtView does not play
any music when it broadcasts. It could, it could maybe send
you the label that it added or changed or something.
But it doesn’t, that’s okay. We don’t care, because all we
wanna know is that something changed so we can say
documentChanged, right? That’s it, now, of course, we need
to stop listening to this. When is a good
time to do that? I’m gonna do that
when you hit close. And I’m gonna do it whether or
not you successfully closed because I’m gonna
get dismissed. So I’m gonna most definitely
stop listening here. And I’m just gonna say
if I can let observer, observer=my emojiArt.View
observer, art view observer. Then I’m gonna ask
the notification center, the default one,
to remove that observer. And that’s it, so this is quite
a bit simpler than delegation, on both sides. I’s
a little easier to do this. You don’t have to implement
that another method. You don’t have to set
yourself to delegate. You do’t have to do that. You just start listening and
stop listening and you’re going to find out. So
that’s why we use notification a lot of times in place
where other times we’ve used delegation and it’s true
in other classes, as well. All right, so let’s go see if
we broke anything. Cross our fingers that removing
delegation entirely from our mode emoji.Art.ViewController
did not break anything. And luckily, we have that
other observing going on, so we’ll be able to tell.
So here’s apple bee, let’s bring up our Console
there, change to normal, that’s good. Now, hopefully
when we drop something in, hopefully, that caused
the radio station broadcast to happen so that we notice
something is different. And hopefully, this is going
to auto save in a moment, and we can force the issue
by threatening to go somewhere else. Woo, it
did it. So, it must have been that our radio station worked.
And we noticed that change, otherwise we wouldn’t have
auto saved there. Okay the last thing we’re gonna do
is use KVO to rip out some of that code that’s calling the
delegate and posting down in my gesture view. Basically
what I wanna do is go to my gestures right here,
and I wanna remove this code. See, this is the code where
I’m telling my delegate and posting on the radio
station when, in this case, something moved.
So I want that out of there, and then down here for resize,
this is when we resize, I want this out of there.
So I’m just gonna delete that. But I obviously, still need
to tell people when I change. So I’m gonna go back to my
ArtView here. And as soon as I add a label, I’m going to have
that label be observed for its center changing. And if
its center changes, I’m going to notify my delegate and
broadcast on my radio station. ‘m basically gonna
do this right here. So how do we do that? The
trickiest thing about, this, it’s actually quite easy.
We’re just gonna to label observe, and what property observing /.
Center. And when we observe, we get
a closure. The closure’s gonna pass the label back to us, and
that little changed object, right there. And we can do
whatever we want in here. And what do we want to do?
We want to do this. Tell our delegate and tell
the radio station something changed. But remember observed
returns a cookie. And we have to keep that cookie in
the heap as long as we want this to happen. So I’m gonna
do that by having a little private var which I’m gonna
call my labelObservations. Which is gonna be a dictionary
with UIViews as the keys and these NSKeyValueObservations
as the values. Now putting things in this dictionary is
gonna keep things in the heap. But only as long as this
EmojiArtView is in the heap. As soon as this EmojiArtView
leaves the heap this will leave the heap and
all the observations will leave the heap, woo-hoo.
So that’s what’s great about this, not having to do
that remote observe, remove observer thing like you
do with notifications. Because when things leave the heap
naturally the observations naturally stop. However, what
if we don’t leave the heap and we remove that subview.
We don’t have any, actually have any UI
to remove our emojis. They once they’re in there,
they’re there forever. But we could imagine putting some
sort of gesture that would remove them, so we wanna
anticipate that day and I wanna make sure we remove
it. So, first of all let’s put the observation,
KeyValueObservations in here. I’m gonna say
labelObservations sub the label=
this observation. So this the labelObservation
for this label, right. Now I have to whenever this view
gets removed from super view, I have to let this
observation leave the heap. In other words, I will have
to remove it from here. Everyone understand that?
So how do I do that? Well, luckily, there is
a nice method in view called willRemoveSubview.
And of course, we’re gonna call
super.willRemoveSubview. And this gets called anytime
a view gets removed from me, which is perfect. All I’m
gonna say here is I’m just gonna check to make sure that
this view that’s being removed is actually in the
labelObservation tier. So I’m gonna say if LabelObservations
subview does not equal nil, in other words it will have
an observation for it. Then I’m gonna set
the labelObservation for that subview to nil.
Boom, it just left the heap. As soon as I clear that thing
out of this it went away. It stops observing which
is exactly what I want, everyone got that? So that’s all we need
to do to do this. Let’s make sure we didn’t
break anything here. Okay so we got our Apple Bees right
here. Let’s change something. Okay let’s take this eight
ball and move it over here. And then let’s try and
threaten, oops let’s get our console
up here. [INAUDIBLE] here, okay let’s threaten
to go somewhere else. Woo-hoo, it auto saved!
It worked again. All right, sound good?
Back to our slides. Good timing here.
Now you remember we talked about the view
controller lifecycle right? View will appear, view did
appear, all these things. Well the same kind of thing
happens with your application and it kind of goes through
this chart up here. So, I’m going to talk about
how it transitions through all these stages, but first I’m going to talk about
the stages. So first of all there is Foreground Inactive
and that is where your code is running, but you’re not
getting any UI events. So you can’t do anything. So you can
only do kind of preparation work in this space. Then
there’s Foreground Active. This is the normal
state you’re used to. Getting UI events, view
controllers coming on screen, segueing, you’re
doing all your stuff. This is the normal running
state of your app. Then there’s Background.
In the background your code is running, you are not
getting any UI events, you never live here for long, maybe 30 seconds. So this is
transitory state, so anything you do in the background state
you gotta do it fast. And then you go into this state
Suspended. Here your code is not running. It’s important
to understand no code in your app anywhere runs. Your app is
not getting any CPU cycles. Now what’s important
about this state is that you could be killed at anytime
in this state. All right, so let’s talk about how
we transition here. One transition is launching your
app. So when you launch your app, you go from not running
where your binary is not even executing, to briefly,
the foreground inactive state, and the foreground active
state. So you do pass through that foreground inactive state
briefly on your way to running when you launch. Now, another
important one is when you switch to another application,
right? So you’re the active app,
someone’s using you, and then they switch
to another app. And when that happens, you go
up to Foreground Inactive for just a moment, and then all
the way down to Background, you sit in the Background for
maybe 30 seconds, and then you move to Suspended.
And now from Suspended either
you get reactivated, if they come back to you, or
you get killed at some point. Those are transitories.
When you get killed, you go directly from
Suspended to Not running. You don’t pass through some
state where you get to run any code. Let’s talk about how you get notified for
all of these transitions. What happens and what
you’re supposed to do. Now, all of these things
I’m going to tell you, by the way, not really that
important. Because a lot of things are taken care of for
you. For example, UIDocument, you notice how when we
threaten to go to another app, it autosaved. It knows about
these transitions. It’s doing that for you, so you don’t
even need to do anything. And that’s true of a lot
of things in iOS. So I’m gonna show you
all of these things. And the way you do it,
but most of the time, you don’t even need to do
anything. You just need to know that these
transitions are happening. All right, so the first
transition is from Not running into this Inactive state,
this Foreground Inactive. This is kinda like preparing
your app. When this happens, like all the things that
happen here that I’m gonna talk about, a method in your
AppDelegate.swift, you know that stepchild that we keep
foisting off into supporting files. Actually we did look at
it last time. Remember it had the thing where you’re
opening the URL? Remember we had that little code in there
that we were talking about, that UI document browser view
controller, handles opening the URL for us? So
we have looked in there. But there’s a lot of
methods in there. And that’s what all of these
transitions have is they call methods in there. And you’ll
see there’s stubs in there. If you go look at it there’s
stubs in there, that have commented out stuff that
kinda tell you about them. So this is all pretty
well documented in there. By the way,
all of these transitions also are broadcast on
radio stations. So you can just sign up and
put a closure and want this transition
to happen, a closure could be executed,
all right? So that’s important to know as well. Not so useful
for the very first one which is application will finish
launching with options. And application did finish
launching with application, cuz that’s one of the first
time you actually write your own code. And notice that that
thing has a little dictionary passed in, right? Application
will and did finish launching with options.
That dictionary tells you why you were launched. Now,
why would you be launched? Well, of course the user might
have touched on your icon. That’s most of the time.
But you can also get launched because someone wants
you to open a document. We’re EmojiArt, and someone wants us to open
an EmojiArt document and we’re not running, we could
get launched to do that. You can also set up things where
you get launched when the user walks by a dry cleaner.
You can actually register a Place in the world and walk
by, boom, you’ll get launched. You can also have this
activity continuation thing, where you’re working in
emoji art on your iPad, and then you switch
over to your iPhone. And then in the corner there’s
a little icon you press. Now you’re right back in
emoji art where you were. Well that might have to
launch you. You might get a push notification. You’re
using Cloud Kit, something in your database changed, you get
woken up to say, hey, look, you got a push
notification for you. So there’s a lot of reasons you
get woken up, and launched, and that dictionary will
contain all the information you need to know about why. It
used to be that an application will and did finish launching.
We built our UI. We created a split view. We
created a navigation control. We put a view controller.
We never do that anymore. I only mention this because,
your final project, you’re gonna go out and Google
things and look Internet. And you’re gonna see people say,
go create a split view in your ApplicationDidFinishLaunching
with options. No, we don’t do that. Storyboards,
that’s how we do it. Those answers were
pre storyboard. Or someone who never got the
storyboard story. We build our UI in storyboards, not in
these method, in this method. All right, the next transition
is actually coming to that inactive state
from the other side. You were the active app, and not you’re not gonna
be the active app. Probably because the user
clicked on another app. This one is
ApplicationWillResignActive, because that’s
what’s happening. Here you wanna think of
this as a the pause button. You wanna pause whatever is
happening in your app right here. So let’s say I use the
example of an Asteroids game. Your shooting Asteroids. You
want the whole Asteroid field to pause when you get this.
And then the next one here is a inactive to active,
that, unpause. So this is
ApplicationDidBecomeActive. So you kinda wanna have a pause,
unpause thing here. Now, with a lot of apps, it doesn’t
make sense. You never pause or unpause. They’re not that
kinda app. They, they just are what they are, so
you don’t have to do anything. But if you have an app where
things would make sense to pause, this is where you
pause and unpause in these two things. Now, this one,
right here, is, someone clicked on another app, you’ve
gone through active, inactive, now you’re going around
to this background state. This is
ApplicationDidEnterBackground. It’s time right here to
batten down the hatches. Close your files, get yourself
in a situation where you could be killed. You’ve got about 30
seconds here to prepare to be killed.
You might not be killed, but you might be. So you wanna
not have any files open, that are gonna get corrupted
if they get closed, or an unsaved data in your app,
close things up here. and you get 30 seconds to do it.
You can ask for an extension, short extensions of time,
but if you ask too much, the system will stop granting
you those exceptions, extensions. So pretty much think about,
you’ve got 30 seconds or so to get your hatches battened
here. The next one here is applicationwillEnterForegro-
und. So here, you went down
the background view, you battened down the hatches,
and you got activated again. You didn’t get killed.
Here you wanna un-batten down the hatches. Open back up the
things that you had closed. Now, a lot of times you don’t
need to do anything here, because you’re opening up
things that you closed in the battening down
the hatches, on demand anyway. If you tried to
access a file and it’s not open, well,
you’ll just open it then. So, oftentimes you don’t have
to do anything here, and I kinda recommend writing your
code in that way. So that you don’t really ever have to
un-batten down the hatches. So that’s, all the things
that happen. And of all those things you
get radio station, all those things that have methods in
the app delegates you can do. But the AppDelegate does some
other things as well in there. For example, the opening
URL thing we saw last time, it also can do
background fetching. Which is kind of cool. Let’s say you have
a Twitter client, or something like that, and when
someone launches your app, you wanna show them
the latest Tweets. Well, you can actually say to your
app to fetch the latest Tweets in the background, even when
your app is not running. And what’ll happen is, it’ll get
launched, but it won’t come on screen, and you’ll be in
that background state for a little, little bit of time, where you’re allowed to make a
couple of network requests for your 30 seconds or whatever.
And then you go back to sleep. So, you can do that with
AppDelegate. It also manages data protection. I don’t
know if you know this but, when your device is locked in
the lock screen, apps cannot see the data. It’s encrypted.
It is fully encrypted, so you, the apps couldn’t do
anything if they wanted to. So, the AppDelegate will tell
you what’s going on about when you can access the files,
things like that. There’s also a UIApplication, which the
AppDelegate is delegate of. We never subclassed
UIApplication, we use the AppDelegate to
configure it’s functionality. However, UIApplication does
have a few interesting things. Like, it has a method so you
can open a URL in another app. So, your image gallery, and
maybe you asked to open an emoji art document. You
can ask using that open URL. Here’s where you register for
push notifications. So, this is something you
have to do if you want that Cloud Kit thing to notify you.
You have to register for push notifications there. You
can set the fetch interval for that background fetching
I talked about. Here’s where you ask for
more time, if you’re in the background mode, and
you need a little bit more time to finish up. That’s
happening in UI application. The little spinner in the top
left of your device that says there’s network activity,
that’s controlled with this bool.
Unfortunately it’s a bool. So if you have multiple
threads acting as a network, they gotta share this bool,
it’s kind of annoying, but. And you can also
find out about things, like how much time do I have
left to run in the background? What is that preferred content
size category, you know, the slider for the font size?
What state am I in? Am I in the foreground, the background, where am I? You can find all those things
out with UIApplication. All right, quickly Info.plist, we
already saw Info.plist in your homework. You used it to add
that app transport security, right? You can actually
edit this directly in XML, you just right click on it and
switch to sources XML, you can do that. will get a snippet of XML from
somebody that does something, enables something in plist,
and you’re gonna paste it in here. But usually we don’t
even edit the plist thing directly like we do with
App Transport Security. We edit it in
the project settings, like we did with
the document types, right? The document types we had for
Emoji Art View, and for your image gallery. We edited
that all in project settings. And the project settings is
mostly editing the Info.plist indirectly. And finally,
we have the capabilities. We talked about this
with Cloud Kit. There are certain things,
that to use them you have to turn them on. This
capabilities tab inside of your project
settings like this. Some of these things require
servers, like Apple Pay, and iCloud, and Game Center.
Some don’t, like Maps, and Inner App Audio, Home Kit,
none of those do. The things that require
a server, you can only turn these on if you are a member
of an Apple developer program. That costs $99 a year. And
you can kinda see why that is, because to access these server
technologies, they’re kinda needs to be stuff in that
server that knows about you, and this providing stuff.
Well, somebody’s got, they gotta
know who you are for real. You can’t just be some
random Apple ID out there. You wanna be registered
in the program. And the $99 seems to me to be
mostly an administrative fee. That’s not very much money for
the amount of functionality that you’re getting
with all these servers, push notifications, all these
things. It’s all covered in one $99 per year fee. I don’t
have time to cover all these, but this is a great place
to go look for interesting, not covered in lecture things
to do. Go look through this list and see if you can find
something fun to do in there. All right, that is it.
On Wednesday, we’re gonna talk about super
important topic, and I, this is the last topic I cover,
really, before you launch into your final projects this week,
which is segues. We know about show segues, and
show detail segues, right? The navigation controller and
the split view controller. And we know about modal
segues too, a little bit. We put put up our emoji
art document modally. But we’re gonna learn pop over
segue’s, more than just for alerts, but pop over
segue’s in general. Also, unwinding segue’s, and embed
segue’s, two kind of under appreciated segue’s that you
can do that are kind of cool. We’re gonna learn all about
that, and I’ll be demoing it all on Wednesday as well.
Next week is Thanksgiving. So, you get a week off.
That will be great, and then we’ll back at it
the week after. All right, see you on Wednesday.
>>For more, please visit
us at stanford.edu.