>> Stanford University.
>> Okay. Well, welcome to
CS 193P fall of 2013/2014.
Today we're going to
continue our discussion
of attributed string from last
time and talk about UITextView,
which is basically a mutable
attributed string viewer, okay?
It's kind of like a UILabel
but much more powerful.
And we'll talk about that.
Then we're going to talk
about a very important kind
of conceptual thing in iOS
7 -- or in iOS in general --
which is view controller
lifecycle.
So that's just the lifecycle of
the controller part of your MVC
and how it gets notified at
different times in its lifecycle
about what's going on.
Then we're going to talk
about the radio station
that I referred to in MVC.
We're going to talk about it
in a little different context
that we see in MVC
because I just want
to introduce it to you now.
And then throughout
today's thing --
so I'm going to be
-- slides here.
I'm going to be stopping
every once and while
and we'll do a little demo.
And then we will move back to
the slides and back and forth
as we cover various topics.
Okay? So let's start
with UITextView.
Like UILabel in that it displays
text but way more powerful
because the text is multiline.
UILabel, if you want it to be
multiline, you kind of have
to say how many lines it is in
advance, whereas UITextView,
as many lines as it needs.
It's also scrollable, editable,
or just selectable if you want.
And of course, you get all
the mutable attributed string
setting of various things like
colors and all that stuff.
So UITextView, super powerful
object but very easy to use.
The way you use it is that
it has a property called
"text storage," which
is an NSTextStorage.
NSTextStorage is a subclass of
NS mutable attributed string.
So you get this text storage,
and you can just start setting
attributes or if it's editable,
the user will start editing it
and the attributes will just
show up on this mutable string.
It's a super great programming
interface new in iOS 7.
Okay. It's having a mutable
attributed string be just vended
like this by UITextView
and editable on the fly
by both the user and
by you is all new
and it's really incredibly
awesome and easy to use.
There are some methods on
UITextView like, you know,
property font where you
can just set the font.
Understand, though, that
when you set the font,
all it's doing is going
through every character
in the mutable string
and setting the font
attribute name --
font, you know, that
thing -- to this font.
So remember that bold and italic
are attributes of the font.
Okay? And so is the
size, actually.
So if you call this
method set font --
you know, call the set
font setter there --
it's going to blast
all of your bolds,
and italics, and size, okay?
So you be a little
careful of that.
If you want to set the font,
though, of every character
and have that stuff preserved,
just do a little for loop,
go through all the attributes
in the mutable string,
get the font that's
already there.
You can grab the symbolic
traits that are off
of it using the symbolic traits
method in UIFontDescriptor
and then create a new font
that is the font you're trying
to set, plus those traits,
and then set it back
as the attribute.
So a little for loop
there to do that.
But I just want you to
be careful about methods
like set font, which are going
to set the font attribute
of all the characters, okay?
UITextView has incredibly
advanced text layout mechanisms.
For example, you can specify the
container that the text is going
to be in and it can even
have exclusion zones.
So if you had an image that
was dropped in the middle
of your text and you wanted
text to flow around it,
even if it's funny-shaped
thing -- you know, image --
you can flow around it.
And you just -- it's
so easy to do it.
Unbelievable.
You just create a Bezier path
that encompasses the thing
you want it to flow around.
You just set that
as an exclusion zone
in the text container
property here of UITextView,
and it will just flow around.
So we're not going to talk
about that advanced stuff.
It's all part of Text Kit,
which is new for iOS 7.
The layout manager is the
thing that lays out the glyphs.
So it takes all the characters
and all the attributes and stuff
and it laying out the
glyphs one by one.
For those of you who don't know
what glyphs are, they're kind
of how you represent a character
or a sequence of characters
on screen with some things.
So the layout manager is the
thing that lays the glyphs
out inside the text container.
So if you're interested in
typography or you're going
to do a final project that has
a lot of text layout and stuff
in it, this is where
you get started there.
Okay? So let's have
a demo where we kind
of combine all the things we saw
in last lecture in
this UITextView.
I'm going to call this demo
"Attributer" because we're going
to be doing attributed
strings here.
And it's going to
look like this.
It's going to be
a totally new app,
totally unrelated to Machismo.
So I'm going to say
create new project.
Let's go ahead and
also hide others here.
Well, we'll do it in a second.
So I'm going to do a
single view application.
We almost always start
with that, a single MVC.
This demo I'm eventually
going to make
into a multi-MVC application
at the next lecture,
but we're going to
start here with this.
So I'm going to call
it Attributer.
I'm going to have the
class prefix be attributer
so that our controller is called
"attributor view controller."
Just do that.
I'm going to put
it in Developer,
same place I have Machismo.
This is my home directory,
Developer.
I'm not going to
use source control.
And here we go.
So this is just a regular
app just as you're used to.
Again, I like to move
these delegate things
into supporting files
because we're not really going
to be doing the delegate.
This quarter we might
actually do the delegates
when we start talking about
multitasking in iOS 7.
But for most of the
time you can just kind
of move that out of the way.
Here's my blank storyboard.
Again, I'm going to go
down to small size instead
of the tall size
just so it fits.
Okay, there's no reason to do
that, except for that it fits.
By the way, you're welcome
to use the larger size
in your homework if you want
because as I ask you to do more
and more in the homework,
then you kind of need more
and more space, which is fine.
Of course, we need
to think a little bit
when we design user interfaces
that this application might run
on some users on smaller
phones and on some users
on larger phones, right?
So we kind of need a user
interface that can stretch.
And next week we'll be
talking about autolayout,
which is a mechanism in iOS for
you to design a user interface
and specify how it
stretches and shrinks, okay,
which is really important.
And not just on different size
iPhones but different devices --
iPads, you might be using them
in a little window inside
an iPad, etc. We want
to make our views of
our MVCs be shrinkable
to at least some extent.
And of course, don't
forget device ration.
When you turn your device,
it all of a sudden gets
wider than it is tall.
Okay? Well, everything
needs to move
around to deal with that, too.
Okay? So we'll talk about
all of that next week.
So let me show you the
user interface I want
to build here first so that
you can kind of understand
where I'm headed, and then
we'll write the code to do it.
It's going to be primarily
centered around a UITextView.
So here I am looking at
all my various things
that I can drag out.
So I'm going to go down
here to UITextView,
which is right --
where is that thing?
Too far down.
UITextView -- I can't find it.
It's right there.
Okay? So UITextView displays
multiple lines of text.
So I drag it out.
By default it wants to be
the whole size of the screen.
But I'm actually going to put
some other buttons and stuff
in here, so I'm going to
resize this to be smaller.
I also want it to have a
little bit of edges here.
Now, notice that as I
do everything the UI,
I'm using these blue lines.
And I haven't really told
you exactly why that is,
but when we start talking
about having these
flexible-sized views
that are going to
want to resize,
these blue lines
play a crucial role.
And so when you're building your
UIs, use the blue lines as much
as possible because then when
we start doing autolayout,
the blue lines are going to
help the autolayout system kind
of get a clue as to what
they should be doing.
All right.
So I'm going to have
this text view here.
And what I want to
do is have some text.
And I'll just use
the default text.
If you look over here when
you create a text view,
you see you get this kind
of pseudo-Latin text here.
Then I'll just use
that as the default.
So that's going to be
the text that's going
to be in this one I run.
And if I run this, I'll
just get this text.
But what I want to be able to
do is select some of the text.
So I'm going to make this
text selectable, okay --
not editable, though;
just selectable.
And so I can select
words in here.
And I want to be able to
change the color of the words,
maybe put a little outline
around the characters, okay?
Do some fun stuff that we can do
with attributed string in here.
And what am I going
to allow us to do?
Well, let's see.
Let me go get some buttons
down here at the bottom.
How about let's allow outlining.
So I'm going to create a button
down here called "outline."
And of course, let's
also let us unoutline.
So I'll create another
button up here.
I'll call it "unoutline."
That's probably not a word,
but we know what we want.
Again, I'm going to use the blue
lines to try and get things,
you know, lined up
as much as possible.
This guy, let's put him
right in the corner.
These guys will line
the base lines up.
That's what the double
line right there means,
that the baseline of the
other button line up.
And we got, also, this
right line was lined up.
So they're going to stick to
the edges and stay lined up.
So we'll allow outlining
and unoutlining.
And then also, I'm going
to allow setting colors.
And the way I'm going to
do that is kind of fun.
So let's get a button out here.
This is a good way to talk
about if I'm resizing,
I want this button
to be 64 by 64.
I know that that's a good size.
And I could try and get it
exactly the size I want.
But it's actually much easier --
if you know the size you want --
to go over here in
the size inspector.
You see this size inspector?
And you can just type in,
"I want 64 by 64," okay?
So this size inspector,
we're going to see
when we start talking about
autolayout a lot there's going
to be a lot of stuff down here,
describing how this
thing gets constrained
when things change size.
But it's also good
for setting the size.
And then once the size is set,
I'll move into a
nice spot like that.
Now, I could put, like,
the word "red" here
and make this a button that
has the word "red" on it.
And I could make
the text be red.
That's what I want
this button to do.
When I click here, I want
whatever's selected to turn red.
But instead of using words, I'm
actually going to use the color.
I'm just going to
go to the inspector.
And since a button inherits from
control and control inherits
from view -- see how that
inheritance hierarchy is working
in the inspector -- I'm
going to go down here
and change its background color,
which is the same thing we did
when we set the background
of the whole view to green.
And I'm going to set this one
to -- let's say this one's red.
Okay? So now I have a
nice red button here.
And when I click on this,
I'm going to have to wire it
up to make this turn red.
So let's make some more buttons
here of different colors.
Again, I'm using the blue lines.
See how they're snapping
in place?
Okay. Getting blue lines --
definitely want blue
lines as much as possible.
So here let's make this
background be green.
I'll make this one be
orange, make this one be --
oh, I don't know -- purple.
Okay? So now we have some
colors and some outlines.
And then let's also
make this thing --
well, let's put a headline
at the top here, too.
So let me grab another button --
actually, let's do
a label for this one
because we're not going
to make it clickable.
So I'm going to put a
label here at the top.
I'm going to put something
like "CS 193P Rocks."
Okay. So that's just going
to be my title of this thing.
I want it nice and centered.
Let's move this up
so that it's locked.
Let's resize it so
it's maximum space.
It locks. And so now I've
got this nice user interface.
I've used blue guidelines
for everything;
everyone's sticking
on a blue guideline.
That's going to be really
advantageous for us when we try
to do autolayout with it.
Now, let's talk a little bit
about the fonts I
want to use here.
And I told you in the slides
that when you're displaying
user content, okay,
you want to use the
preferred fonts of the system.
Okay? And that's what I'm
going to do, both for this guy.
This is clearly the
user content.
These two buttons
are not user content.
They're going to stay
the system fonts, okay,
because they're buttons.
But this title and this body
are kind of user contents.
You could argue that the title
is not quite user content,
but it kind of is.
It might get localized
to another language
or it might change,
depending on what's going on.
I don't know.
But it's really kind
of a headline.
So I'm going to use
the headline font
to display this guy
right here --
actually, I also
want this centered.
All right.
So let's make sure
that's centered.
And so the way you
pick the headline font,
the preferred font
which is headline,
is you inspect the label and
you go here to the fonts.
And you can see that
it's currently set
to be a system font.
And I'm going to go down here to
text styles and pick headline.
And that's basically in the
code like saying preferred font
of a text style headline.
And you can see it change there.
Kind of got a little bold to it.
It's now the headline font.
And the same thing here, the
text view, I'm also going
to set it to use
a preferred font.
But in this case I'm
going to use the body font
because this is clearly, like,
the body of this
content in this window.
So now I've set these things to
have the preferred fonts rather
than the system fonts.
And that's pretty much all
that's required to set that up.
So that's my UI.
All right?
So yeah, question?
>> In iOS is there an easy
way to round out the corners
of those buttons, or do
you have to go through,
like, a lot of masking?
>> Yeah, so the question is:
If I wanted these to be, like,
rounded rect buttons -- which
it's not really a thing in iOS 7
to have rounded rect buttons,
by the way; it was a thing
in iOS 6, but not so
much a thing in iOS 7 --
how difficult would this be?
And the answer is it
wouldn't be that bad.
It wouldn't be that hard.
There's a mechanism.
Rounded rect is a one-liner
to create a rounded rect.
And probably we wouldn't
make these UI buttons;
we'd just make them views.
And it's really a one-liner to
have a tap gesture, to tap on it
and cause it to do something.
So, you know, a few lines
of code is really
not that difficult.
In fact, you can make it not
just rounded rect but any shape
that you wanted there, whatever.
Question?
>> Is there any way to include,
like, CSS in it though or no?
>> So the question is: Is
there any way to include CSS?
Not really directly.
However, these preferred
fonts, for example,
are plugged into the CSS system.
So if you have content in
your app that is coming
from CSS source, you know,
on a web view or something --
we haven't talked about any
of that yet, but you could do
that -- the fonts can match up
and all synchronize
with each other.
So there's some synchronicity
there,
but you can't directly display.
Okay. So let's look at the code
to make this user
interface do what we want.
So I'm going to get my
system editor up here.
Let's put that right
on the edge.
Let's make some more space
so you can see more code.
And you can see that my default
view controller has this method
here, viewDidLoad, which is part
of the view controller lifecycle
that we're going to
talk about in a second
and also did receive
memory warning,
which is not strictly
speaking part
of the view controller lifecycle
but I'm going to talk about it
as part of the view
controller lifecycle.
I'm not going to
demo that today,
but I am later going
to demo viewDidLoad.
So we'll leave that
in there for now.
Right now it doesn't do anything
except for call [inaudible].
Okay?
So what do I need to do here?
Couple of things.
One, I'm going to want
to be setting the mutable
string attributes of this thing,
so I need an outlet to this.
So I'm just going to control
drag here to create an outlet.
I'm going to call it "body,"
okay, because it's kind
of like my body text view.
And you can see that
it's a UITextView.
And I'm going to be able to
send a message to this body
to get its text storage
mutable string.
And then I'm just going to
start setting attributes.
Okay? It's as simple as that.
You know, I'm also going
to grab one to this,
and you'll see why later.
I'm going to call this
my "headline," okay?
And so I could call that my
"header," or my "heading,"
or "title label," or
something like that.
I'm going to call it "headline"
just here to emphasize
that we're talking
about preferred fonts
because I'm going to be showing
that in the demo as well.
So we've got this
body in the headline.
We could conceivably set
things about the headline.
I don't really have
time for that,
but we will be setting
things in here.
We've got these colored buttons.
Let's do those first.
So I'm going to control drag
here to have an action sent
when we press on that button.
I'm going to call this action
"change body selection color
to match background of button."
Okay? Now, you might
laugh and say, "Whoa,
that's a long name method."
But long name methods are
kind of preferred generally
in Objective-C and especially
in iOS because Xcode's going
to help you escape
complete these things.
And if you can have a
method name like this
that really matches and
says exactly what it does,
that can be a good thing.
It's an art of programming
thing.
I'm going to change the
argument to be a UIButton,
just like we did
before in Connect.
So what does this method do?
Well, hopefully with that
long name it's clear what
that does, right?
It changes whatever
the selection is
in our body right here, it
changes the color of that
to match the background
view of this button.
Okay? That's what this
method is going to do.
This method is one line of code.
Okay? So let's look at
that one line of code.
We need to set attributes of
the mutable string of our body.
So I'm going to say
self.body.text storage.
Now I have the NS mutable
attributed string --
text storage is a subclass of it
-- but it is an NSMutableString.
And I just want to
add an attribute,
which is the foreground color
of whatever's selected there.
So the attribute is called
"NS foreground color
attribute name."
Okay? The value -- that's the
color we want to set it to --
well, I said we're going to
have it match the background
of the button.
So I'm going to say sender,
which is the button
that's sending this thing,
background color, okay?
And then the range is what range
of this text view's storage do
I want to set to be that color?
Well, I said I want it
to be the selection --
the body selection --
so there's a method
in text view called
"selected range."
And it returns an NSRange
of what's selected, okay,
what the user selection is.
Okay? So you can see one line of
code, and we've got our color --
all four color buttons --
working as long as they're
all wired up, which we know
that this one is, right?
Okay, because we
wired that one up.
There it is right there.
We haven't wired this one
up, but let's do that.
And this one.
And this one.
Okay? So let's go ahead and run.
We'll try and see if we
can run it on the device
over here if that works today.
Hopefully no technical
issues will arise.
Now, this is an iPhone app
that we're running here,
and we're running it on an iPad.
My demo machine happens
to be an iPad.
So this is running kind of in
iPhone emulation mode, okay,
which is actually better
in iOS 7 than it was
in previous versions of iOS.
It's not quite exactly the same.
You notice that this status bar
at the top, you don't get the,
you know, what your carrier is,
and the battery life,
and all that stuff.
That's kind of cut off.
But otherwise it's
pretty similar.
So you can see that we got
that kind of pseudo-Latin text
in there, and it's scrollable.
And it's also selectable.
So I just double
tapped on that word.
And we got it now.
You get things for free on
this, like defining words --
looking them up in
the dictionary.
So if we hit define right here,
it goes and looks it up --
not found, not understand,
no surprise there.
But you can look that up.
And of course, hopefully
all our buttons work.
So let's try red.
That worked.
And orange and purple.
Okay? Green.
So that's working.
That's setting things right.
I could actually extend
my selection, go orange.
Sets it all orange.
Pick another word, red.
So that's working.
Super easy.
Okay? Everyone understand
what we've done so far?
So now let's go on and
do the outline button
and the unoutline button.
So I'm just going to
control drag from there.
I'm going to call
this "outline."
I don't need any argument
here because I'm not looking
at the button to
determine how to do it.
And in fact, in spirit of
not long message names,
let's call it "outline
body selection."
Okay, because that's kind
of even clearer exactly what
the outline is going to outline.
So let's do that.
Here we have outline
body selection.
Again, this one's same thing as
before -- body text storage --
and we're going to
add attribute.
But actually, to do an outline
we need to do two things.
One thing is we need to
set the stroke width, okay?
That's the width that the
character gets stroked --
not filled but stroked,
its outer edge.
And we also want to set
the color of that stroke.
I want it to be black.
Okay? So if we have a word
and its color is selected,
it will still fill with that
color, okay, because I'm going
to specify a stroke that
does a fill and a stroke.
But the outline's
going to be in black.
So when we do add attribute,
we need to do add attributes --
plural -- because we're
going to add two attributes.
Now, this is a dictionary,
and I can just create this
dictionary right on the fly here
with our at sign curly brace.
And one of the things we
want is the stroke width.
So here's the stroke
width attribute name.
And I'm going to set the
stroke width to minus three.
Okay? Minus three, if you'll
recall, means stroke width
of three and also fill.
If I said stroke width of at
sign three, it would not fill.
It would be clear.
Right? In the middle
of it would be clear.
So we don't want that.
We want to fill.
Whichever color we
pick, we want that to.
So that's that.
And then let's also set
the stroke color attribute
to be UIColor black color.
So I'm just doing this mostly
so you can see how to put,
you know, an actual color
in there instead of here
where we grabbed a color
from somewhere else.
You can use these class
methods in UIColor to do that.
And we need the range.
Same thing as before:
Selected range.
Okay? So now we're going
to add both those
attributes to outline it.
That's all we need there.
Let's do unoutline
while we're here.
Save ourselves a
little bit of time.
I'm going to call this
"unoutline body selection."
Done. And just again to
show you a different method,
let's unoutline by removing
any stroke width attribute.
I could probably set the
stroke width to zero as well.
But I'm going to remove
so that you can see how
in NS mutable attributed string
we can remove attributes.
We just say "Remove attribute
NSStroke width attribute range
self.body.selected range."
Okay? So that's going to
remove that attribute.
We don't really need to
remove the stroke color
because if it's not
being stroked,
then the color doesn't matter.
So it's kind of in there.
It's a little extra.
You could argue maybe
wasted storage.
Although the storage
of attributed string is really
optimized to the nth degree.
Okay? So I wouldn't worry
too terribly much about that.
All right.
So let's go see if that works.
Okay. So let's pick another word
here like this one, outline it.
That is outlined.
It just looks bold because
it's filled with black still.
Okay? Because black was
the color that's there.
But if I fill it with orange,
you can see it looks
a little different.
Right? Or go over
here to this word.
Let's make it red and
then outline it, okay?
Everyone cool with that?
Then we can unoutline as well.
Go back to red.
So outline, unoutline.
Okay? Everyone understand that?
Okay. So that's it for now.
We'll be back to
this in a second.
Yeah?
>> Yeah, I'm not quite sure
that I understand the difference
between the negative
three and positive three.
Like, what's getting filled
or isn't getting filled?
>> Okay. Great question.
So let's just be a
hundred percent clear:
What's the difference
between the negative three
that we have right here,
okay, and positive three?
Negative three means --
in fact, you know what?
I'll show you a demo
of it a little later.
See the button that
says "outline"?
Later we're going to
change it to be outlined.
Okay? And we won't fill it,
and you'll see the difference,
that it's not going to be
filled with a color, okay?
So let's get back to
the slides, though.
And over here.
Next. Okay?
View controller lifecycle.
Okay. So this is important
thing to understand,
the view controller lifecycle,
because a lot of the things
that you're going to control
about how your view controller
moves through time are going
to be controlled by the
methods that are part
of the view controller
lifecycle.
Now, all the view
controller lifecycle is,
is a series of methods,
okay, that are sent
to UIViewController
when things happen.
Now, your controller is a
subclass of UIViewController.
You probably noticed that.
If you look at your code,
you'll see that your controller
that gets created for
you by the template
when you create a new app is a
subclass of UIViewController.
So it's going to be sent these
messages, and you're going
to override them
if you want to find
out when these things
are happening.
Don't forget to call super.
Okay? Why do you
need these things?
Well, you need to be able to
initialize your controller;
you need to be able to find
when you come on and off screen;
you need to know when
your bounds change, right,
your geometry changes.
You got to know these things
for your view controller's view
to successfully live
in the iOS world.
So the start of this
lifecycle is creation, okay?
Most view controllers are
created out of storyboards.
And I told you that
storyboards don't generate code.
You're basically editing
those objects live --
that UI text view,
those buttons --
you're editing them
live in Xcode.
And when that storyboard
gets saved,
they kind of get freeze-dried.
And then when your application
runs, water gets added back
to them and they come
back to life, okay?
So that's the creation
part of the lifecycle.
And we don't really
do much at creation.
In fact, I'm not even going
to talk about creation
until the very end of the
view controller lifecycle.
Even though it is
chronologically the beginning,
it's by far the least important.
So I'm emphasizing that
by putting it at the end.
But after it's created, you go
through the following process.
Your outlets get set, okay?
Got to have those outlets set.
Then your view controller
appears on screen
and it might disappear
from screen.
You haven't seen that
yet because right now you've
only had one view controller
in your whole app.
It only disappears
when the app quits.
But when you have multiple view
controllers, they'll appear
and disappear on screen.
Their geometry changes --
either device rotation
or something else can cause
their bounds to change
of your view of your MVC.
Low memory situations -- again,
not strictly speaking part
of the view controller lifecycle
but that can happen
while you're running.
And at each of these steps
a method gets called.
So let's look at the
first one: ViewDidLoad.
So that's the one we saw in
the code that I didn't delete.
This is a really great place
to put initialization
code for your controller.
You can kind of think of it
as where you would put all the
stuff from your init, okay,
because your init is not
going to get called --
as you're going to see --
for your view controller.
So why is this better than init?
Because your outlets are set.
Okay? Very important for your
outlets to be set usually
if you want to initialize
your view.
Because you want
to set your labels
to say something or whatever.
You know, in the
Machismo game we started
with the cards facedown because
we didn't really know how
to start faceup.
Okay? Well, this is where
you would set the first card.
All right?
You'd draw the first card, have
it -- this is the Machismo,
not your assignment but
what we did in class --
have it start with
the card faceup.
You would do this in viewDidLoad
because here your
outlets are set.
So I can talk to that button.
It was a single button
in Machismo at the time.
But I'm not on screen yet.
ViewDidLoad gets called
before you come on screen.
So it's a great place
to do stuff like that.
ViewDidLoad will only
ever be called once
in the lifetime of
your controller.
Period. Once.
It never gets called
more than once.
Okay? It is a spectacularly
great place
to put initialization code.
However, there are limits to
what can go in viewDidLoad,
most especially geometry code.
At the time viewDidLoad
is called,
the bounds of your
view is not finalized.
It's probably just
sitting at whatever it was
in the storyboard, which may
or may not be what's going
to happen when it's on
screen because it might be
on a little different
device, or different place,
or it might be rotated,
or something like that.
So you do not want to put
geometry-related code --
in other words, any
initialization that has to do
with what the shape of your
view is -- in viewDidLoad.
Okay?
That's the major
restriction in viewDidLoad.
But otherwise, it's
a great place
because it only gets called
once before you go on screen
after your outlets get set.
It's an awesome method.
Okay? Highly recommend it.
Now, just before your view
controller view appears
on screen, you get
viewWillAppear.
Okay? This is a pretty
good place to put things.
It's not really as awesome
as viewDidLoad in some ways.
And I'm not even sure I'd put
geometry-related stuff in here,
as you'll see in a
couple of slides.
However, there are some things
you do want to put in here.
Now, one thing you want to
be careful about not putting
in viewWillAppear is
one-time initialization
that really belongs in
ViewDidLoad because, again,
when you have multiple MVCs
in your app, they're going
to be appearing and
disappearing.
And so viewWillAppear is going
to get called multiple
times, okay?
Every time your view
appears back on screen,
viewWillAppear gets
called again.
So if it's a one-time
initialization,
you put it in viewWillAppear,
it's going to happen every
time your thing reappears.
So what does go in
viewWillAppear?
Well, one thing is if there's
some initialization you need
to do, based on some data
that might have changed while
your view controller's view was
off screen.
Okay? So like your model.
Something changed in your model.
Your view controller
was off screen,
so it wasn't really listening
for changes in the model.
And then coming back on screen,
you better sync up
with the model.
Does that make sense?
Because you were off screen
and now you're appearing.
And so this is a good thing
to put in viewWillAppear:
Synchronization with things
that might have changed
while you weren't visible,
including things that, you know,
were changing before you
appeared for the first time.
Because viewWillAppear,
of course,
gets called the first
time you appear as well.
Okay? This is not view will
reappear; it's viewWillAppear.
Okay. So that's a good
thing to put in here.
We'll talk later in the course
about putting code in here
for optimization purposes
because if you put something
that's going to take lot
of resources, like you're
going to make some network call
in viewDidLoad, and what if your
MVC never appears on screen?
Well, you wasted that time doing
that network call
on viewDidLoad.
Whereas if you do it
in viewWillAppear,
even though you're going
to have to design it --
because if you do
something in the network,
it's going to come
later; it's not going
to be instantaneously
available, that's okay,
we'll talk about how
to do multithreaded,
make that all work
-- kicking it off
in viewWillAppear might be
a little better performance
because you know when
you get viewWillAppear
that your view is going
to appear on screen.
Okay? So it's worth it to
do something expensive.
But that's kind of
advanced stuff.
So I won't worry about
that too much for now.
The view's geometry is set here.
So you could do some
initialization based
on geometry here.
And a lot of people do it
because it's kind of simple.
But there's actually
a better place
to do geometry-based
initialization.
But it's okay.
It's quote "okay to do it
in viewWillAppear" as long
as you understand that
your geometry could change
after viewWillAppear.
In other words, you
can be on screen
and someone could
rotate the phone,
and now your geometry
just changed.
Okay? So you better
deal with that, okay,
that you're not going to get
viewWillAppear when you rotate,
you're going to get
other things.
Okay. You also get notified when
you're view goes off screen.
So that viewWillDisappear, okay?
And what do you want
to do in here?
You don't usually do a
lot of stuff in here.
If you're doing something
like animation or something,
obviously this would be a good
place to stop doing that because
when viewWillDisappear happen,
really you want your controller
to become a good citizen:
Stop using resources.
You're not on screen, stop it.
Okay? You'll get
viewWillAppear when you go back
and you can sync
back up to the world.
But after you disappear, you
kind of want to lay low, right,
in terms of memory usage
and certainly CPU --
you don't want to be using CPU.
So this is a good place
to do stuff like that
and to maybe remember state
that you're going to restore
in viewWillAppear
again, whatever.
Kind of what you might think.
There's also did
versions of these.
ViewDidAppear and
viewDidDisappear.
And that happens exactly
what you might think, right?
ViewDidAppear gets called
after you're now on screen.
Okay? You just appeared and
you just got called, okay?
Same thing, viewDidDisappear
-- you just disappeared.
Okay. Now, let's
talk about geometry.
Okay. I put this
off to this slide.
Your geometry, in iOS 6 they
introduced these really cool two
methods: ViewWillLayout subviews
and viewDidLayout subviews.
This is where to put
geometry-related code.
So viewWillLayout subviews is
called just before iOS 7 tries
to layout your subviews,
tries to layout your view.
Okay? So your geometry
just changed maybe
from portrait to landscape.
And there's a lot of automated
stuff in iOS 7 called autolayout
that will try and move
everything around to fit.
Now, it can't always
do it but it tries.
Okay? So viewWillLayout
subviews is called before that.
And viewDidLayout subviews is
called after it's done that,
after it's made that attempt.
Okay? Now, if there's
some things
that have been moved manually,
you have to move them by hand,
okay, that there's
just no way to express
in the automatic layout rules
where things go, then best place
to do it is probably in
viewDidLayout subviews, okay,
because the system's
already laid things out.
Now you can move around
the last few pieces
that need to be laid out.
But things like buttons,
you know, like that outline
and unoutline button, it's
really easy to make it so that
when you rotate to landscape
they move down to the corners.
Okay? That's what you
probably want there.
Same thing, the text view:
Pretty easy to make it widen out
and get shorter when
it goes to landscape.
Okay? But like in Machismo,
you got all those cards.
When you turn it, you might want
to use some logic to figure out:
Where are you going
to lay the cards
out in a landscape
orientation versus portrait?
Okay? And you're going to
have to do that next week.
Okay? Not this week.
So I want to talk a little
more about autorotation.
So this is the thing
where you turn the phone
and your geometry
automatically gets changed.
That automatic change to the
new geometry only happens
if these conditions are true.
Your view controller
has to return yes
from should auto rotate,
which is the default.
Your view controller has to
return that new orientation
from supported interface
orientations.
That is a method that returns
an e num with landscape
and portrait, portrait
upside down in there.
So you have to say that you
support the various rotations.
I believe by default it
supports all rotations.
And your application
as a whole has to say
that it supports
that new orientation.
Okay? And that is set --
remember when we first built
our application and it ran?
There was, like, all these
kind the settings for our app
that I just waved
my hand and said,
"We'll look at this later"?
Well, one of the settings in
there is which orientations
of a device -- portrait,
landscape, portrait upside
down -- do you support?
Okay? So you have to click
on the ones that you support.
And if you do all these things,
then when the device rotates,
your bounds of your view
will automatically be changed
and you'll get the whole
viewWillLayout subviews,
viewDidLayout subviews,
autorotate,
autolayout, all that happening.
Okay? There are also
methods that get called.
I put them in gray here
because we're not really going
to look at them.
They're rarely needed.
Autolayout and viewDidLayout
subviews are usually going
to cover everything you need.
But if you wanted to get
involved in the animation
of the rotation and all
that, it's all possible.
But we're not really
looking at that.
Okay. In low-memory situations,
you're going to get this message
to your view controller called
"did receive memory warning."
Okay? And low memory doesn't
necessarily mean your app is
using a lot of memory;
it just might be all apps
on the phone combined are
using a lot of the memory
and it needs some of it back.
So it might be sending this
to lots of applications.
It's completely up to the system
so decide whether it wants
to generate this warning.
And your only responsibility
when you get this thing is
to try and free up memory.
Okay? That means in the heap.
And that means setting strong
pointers you have to nil.
Okay? Now, if you
display an image, okay,
if your MVC displays an
image, that's big memory.
Images are a lot of memory.
Okay? Or it plays a sound
-- that's a lot of memory.
But if your thing is on screen,
if your view controller is
on screen, you can't
throw that image out.
It needs to be on screen.
So there's really
not much you can do
when you get did receive memory
warning if you're on screen.
Now, however, if you
have an alternate image
or something that's not on
screen right now, you could set
that to nil as long as you
can recreate it, okay --
either recreate it by getting
it from the file system,
even making network call to
download an image as long
as the image doesn't need
to be instantly available.
But that's an example of how
you could respond to this.
Especially if you're off screen
you could respond to this,
although my argument is
when you go off screen
and you get viewDidDisappear
or viewWillDisappear,
you should free up
that stuff anyway.
Okay? And get it back when
you do viewWillAppear.
Because you don't want
to be a memory pig.
Okay? Now what does it
matter to be a memory pig?
Why do we care?
Well, couple of things.
Okay. First of all, by the
way, only things that use a lot
of memory are things like
images, video, sound --
those can use a lot of memory.
Small things like little
dictionaries with five things
in them, that's using
virtually no memory.
I wouldn't even waste your
time freeing those up.
Okay? That's just going to make
your code complex for nothing.
So we're talking about
good-sized things, okay,
when we say "free things up."
But anyway, why do we want
to be a good citizen here?
Well, iOS has the
right to kill your app
if it thinks you're
being a memory hog.
Okay? If there's not
enough memory on the system
and your app happens to
be using a lot of memory,
it can just come along and say,
"Bam-o, killing that baby."
It's perfectly within
its rights.
If you're a good memory citizen,
it's never going to do that.
Okay? But being a good memory
citizen means you shouldn't be
using a lot more
memory than, you know,
a single MVC that's
on screen right now.
Or if you're on the iPad,
maybe it's three or four MVCs,
depending on what
your layout is.
You know, however much memory,
that would be reasonable to use.
A video in there, no
problem, etc. That's fine.
But if you have, like, twenty
videos sitting in the heap,
okay, you're going to be a
candidate to get blasted.
Okay? So the other thing
is you obviously want other
applications to have as much
memory available to them
when the user switches
back and forth.
If you've got a reputation
as a memory pig like, "Oh,
when I run this app, all my
other apps slow way down.
Oh, it's terrible."
Then on the App Store people
are going to say that,
and you're going to
get a bad reputation,
and people aren't going
to want your application.
So that's another reason
not to be a memory pig.
>> Can Apple check
this kind of stuff
to see how much memory you use
before they approve an app?
Is that a thing?
>> So the question is:
Does Apple go and check
to make sure you're being a
good memory citizen before they
approve you?
I would say I don't know.
I don't work for Apple.
I don't know what's going on
behind the scenes there in terms
of their approval process.
My guess is if they ran your app
and it just immediately
ballooned up a huge amount
of memory, they would
not approve it.
That's just my guess.
I mean, I wouldn't
if I were them.
And you know, certainly
apps that are out there
that have a reputation
of being big memory pigs,
maybe when you submit your
next version or something,
they're like, "Wait a second,
did you fix that memory thing?"
You know what I'm saying?
It's common sense, common sense.
Okay. So that's that.
Okay. Now I told I would
talk about creation
of the view controller.
And so I'm going back and
talking about it here.
I'm only going to
talk about it briefly
because it's really not super
important because viewDidLoad is
where you want most of
your initialization.
But when your view controller is
created, when it's pulled out of
that storyboard and
unfreeze-dried,
your init method is not called.
Okay? A different
init method is called.
The unfreeze-drying init method,
which is a generic init method
mechanism that we're not going
to -- well, we might talk
about it in week eight
or nine of this course.
Not that important.
But that's what Xcode uses
to freeze-dry your apps.
So that init -- you don't
subclass that init, okay?
Okay, it's an init;
I'm not even going
to tell you the name of it.
You don't subclass it.
Instead, when something
gets unfreeze-dried
from a storyboard -- anything,
not just your controller
but even, like, a button
or anything else comes
out of there -- this
method, awakeFromNib --
Nib is an old historical name;
you could think of it as awake
from storyboard --
this gets called.
And you can put in here things
that you might normally
put in your init.
Although, again, your outlets
are not set at this point.
So you're better off
putting stuff in viewDidLoad.
Okay? But if there's some
reason you can't put something
in viewDidLoad -- I can't even
think of a good example why
that would be -- you can
put things in awakeFromNib.
Now, to make this a
little more complicated
but also a little more
correct, it is possible
that your view controller
could be created
in code using alloc init.
It is legal for someone
to alloc init --
init is not the designated
initializer for view controller
but init calls the
designated initializer --
so it is legal for
people to do that.
Not going to happen
in this class.
Okay? We're going to make things
out of storyboards for 100%
of this class, so
don't worry about it.
But the designated initializer
for UI view controller is init
with nib name colon
bundle colon.
Okay? Again, historical
reasons here with old nib files.
And so to be correct, we usually
like to call whatever
we're going to call away
from nib also in
that init method.
And so you use this
little template
where you have some method
called setup or something,
awakeFromNib calls
that, and then init
with nib name says self super
init with nib name bundle --
because that's the
designated initializer --
self setup return self.
Okay? So if you're going to put
awakeFromNib in there, go ahead
and put this little three-line
init with nib name also
in there, just to be correct.
Okay? Probably not
necessary in this class.
I don't think you're going to
need awakeFromNib in this class;
viewDidLoad is what you want.
Okay. So here's a summary of
the view controller lifecycle:
It's instantiated
from the storyboard
or someone could say alloc init,
okay; awakeFromNib gets called
if it came out of a storyboard,
otherwise init with nib name
with bundle gets called; the
outlets get set that comes
from a storyboard; then
viewDidLoad is called;
then when the geometry
is determined,
viewWillLayout subviews and
viewDidLayout subviews --
there should be no colons
there; I don't know what,
that's a mistake -- get called;
then viewWillAppear gets called;
then if the geometry changes
again while it's visible,
viewWillLayout subviews
and viewDidLayout subviews
will get called again.
Okay? If there's auto rotation,
you also get those
autorotation things.
But don't worry about those
because you're usually
doing what you want to do
in viewDidLayout subviews.
Then when your view
controller goes off screen,
it will get viewWillDisappear.
Okay? If you have a low
memory thing at any time going
on there, you'll get that.
That could be while
you're visible or not.
And that's it.
That's the view controller
lifecycle from start to finish.
Okay? All right.
So let's see a little demo
of using the view
controller lifecycle.
So what I'm going to do is
that outline button we
talked about before.
Let's make it so the outline
button is itself outlined.
That would be kind of a good UI.
Okay? So it's kind of a little
more indication of what it does.
Well, the question is: If I have
this outline button right here,
how and when am I
going to outline it?
I can't do it in
Xcode unfortunately.
So I need to do it in code.
But I want it to be outlined
when the thing first comes up,
but -- and I want it
to always be outlined.
So that's a one-time
initialization thing,
but it obviously has to happen
after my outlets are set
because I need to be able
to talk to this button.
So let's make an
outlet for this.
I'm just going to
control drag here.
I'm going to call this the
"outline button," okay?
And I'm going to
take viewDidLoad.
I'm actually going to move
it up to the top here.
Okay. So there's viewDidLoad.
And I'm going to do
exactly what it says here,
do any additional set up
after loading the view.
This should say typically
from a storyboard.
It's funny that that
has not changed.
I mean, storyboards have been
around for -- I don't know --
four, five, six, seven,
something like that.
They're still saying
from [inaudible].
But anyway, viewDidLoad
is the place to do this.
And all we need to do is set the
attributed title of this button
to have the attributes
of outline.
So how are we going to do that?
Okay? And this is important
for you to pay attention here.
You all look awake, that's good
because your homework
that's going to be assigned
on Wednesday is going
to require this.
You're going to have to set an
attributed title of a button.
Okay? Because your cards
are buttons unfortunately.
They won't be buttons
the week after that.
But they're buttons right now.
And so you're going to
need attributed strings
to display what we
want to do next week.
And so you're going to have to
set attributed titles to button.
So let's talk about
how we do that.
First thing I'm going
to do is I'm going
to say NS mutable attributed
string title equals.
So I want to get the
title of this button
as a mutable attributed string
so that I can set the attributes
to be the outline attributes
that stroke width thing.
So the way to do
that is I'm going
to say NS mutable
attributed string alloc init
with string self dot outline
button dot current title.
So whatever's on there
currently, which is the word
"outline" right now,
going to use that.
And then that's it.
That's all I'm going
to do there,
just show you how to
do this, this way.
I could set the attributes
there, actually, but --
oops, did I get that right?
Okay. So now I have the title as
an immutable attributed string.
So now I can set the
attributes in this title.
Okay? Now this title is an
NS mutable attributed string
that I just created.
It's a local variable.
It's created with
the button's title,
but it's a local variable.
So let's go ahead and set
the attributes we want.
Okay? Again, it's very
similar to this down here.
In fact, I'm going to
just copy and paste this
and make one small change.
Okay. So here, instead
of the minus three, okay,
I'm going to make it three.
And that's going to make this
outline thing be outlined
with no blue in the middle.
Okay? So the foreground
color of this button is blue
or whatever the default
is, black.
But I'm going to make
it so it's outlined
with nothing in the middle.
The other thing is I don't
really want this button
to be black, okay?
Because buttons are not black.
Now, what color are buttons?
Okay? And this brings up another
interesting thing we really
haven't had a chance to talk
about, which is the tint color.
Okay? And some of you have
discovered this on your own
because you didn't
like the blue tint
on the green background
in Machismo.
And I applaud you and your
UI instincts to go searching
for a way to change that.
And the right way to change it
is there's actually a global
tint color, a tint color
for your entire application.
And you set that by
going to your storyboard.
See how my storyboard
is selected over here?
And if I go to the
little area here
that has all my attributes
inspector, if I click the left
to most one, which is
the file inspector --
it's inspecting this
storyboard file --
you'll see there's global tint.
Okay?
So global tint affects
all clickable things
in your app everywhere.
Okay? So you could pick a
different color than blue.
And we do that.
The other thing is individual
elements like UI buttons,
they also have a tint color.
Now, usually you don't want
to set them separately,
although a couple people
noticed what seems to be a bug
in the simulator where if
you set the global tint,
it draws improperly segmented
control in the simulator.
I haven't heard back whether
it does it on a device.
But so the workaround was to
set the individual tint color.
So you can set tint
color individual items
or you can set it at
the storyboard level.
Here what I'm going to do,
I'm not going to set it
but I am going to get it.
I'm going to get the tint color
because whatever this tint color
is, I want that to be the color
that I'm stroking it
with, the outline color.
So that is going to be self dot
outline button dot tint color --
tint color.
Okay? Understand
what I'm doing there?
So I want it stay blue or
whatever this color is,
but I want it to
be outlined only.
And then the range, I need
the entire range of text.
In other words, I have this
mutable string title here;
I want the entire thing done.
So I'm going to use NSMakeRange,
and you're going to find
that for C structs
in iOS there's usually an
NSMake whatever you want
that will make the C struct
by letting you specify
the members of the struct.
So in this case a
range has a location --
a starting location --
which will be zero
and it has a length.
Okay? Which is going
to be title length.
Okay? So that makes
a little range.
That's going to set the entire
range to have these attributes.
Okay? Now I have the title
I want as a mutable string,
but I need to set this
back on the button.
Okay? Because I've
only can done this
as a local variable right here.
Because there's no mutable
attributed string in button
like there is in text view
that you can just modify;
you have to get it, make a
mutable version, you know,
edit it, and then set it back.
And the way we do that is
self dot outline button set
attributed title,
title, for state --
UI controls state normal.
Okay? So it's just like set
title but set attributed title.
Okay? So let's see
if that works.
[ Pause ]
Okay. And it did.
So you can see the outline
right there is outlined.
It's not awesomely
outlined, or it's kind of hard
to see that it's outlined.
I might want to go back to here
and set this, for example --
this outline button -- instead
of being just the system font,
maybe I want this to be bold
system font, which -- oops --
which will make it
outline a little better.
So let's go to here, inspect
it, and in the font here instead
of using the system font,
I'm going to use the
bold system font.
And now when I run, it
will look a little bolder.
So it's a little better,
a little easier to
see the outline.
Okay? And it's still a button.
If I click it, it still
outlines the text.
Okay? All right.
That's all I wanted
to show you there.
I'm going to show you another
view controller lifecycle thing.
But first, let's do
a couple of slides.
I want to show you
one other thing,
which I promised I would show,
which is this radio
station thing.
So the way of communicating
between objects
in a blind structured
way, which we refer
to as this radio station
thing from MVC is called
"notifications" in iOS 7.
And we're only going to
talk today about how to tune
into the radio station; we're
not going to talk about how
to broadcast on the
radio station.
And in specific today,
we're only going to tune
into a system radio station,
an iOS 7 radio station.
Later in the course
when we start talking
about building more
sophisticated models using
databases, then we'll really
start using the radio stations
to hear about changes
in the model.
Okay? But today we're just
going to hear about change
in the system because I just
want you to get an idea of what
that radio station looks
like on the receiving end.
And it's really, really easy.
There is a class called
NSNotificationCenter.
It has a class method
called defaultCenter.
That returns a shared instance
kind of like NSUserDefault,
standard user default
did -- a shared instance.
That's the object you use
to tune into radio stations.
And you do it by
sending it this message:
At observer selector
name object.
The first argument observer,
that is, the object that wants
to listen to the radio station.
So in your controller -- because
controllers are the most common
radio station listeners -- this
would probably just be self.
Okay? Add observer self.
This is somewhere in
your controller code.
Selector is the method inside
of the observer that you want
to be called when something
appears on the radio station.
Some broadcast happens.
Okay? Name is the name
of the radio station.
Okay? Which radio station
you want to listen to.
And sender there
-- object sender --
that's if you only
want to listen
to radio station
broadcasts that come
from a certain other object.
Often you pass nil here, which
means if anyone broadcasts
on that frequency,
I want to hear it.
Okay? But it is possible
in certain cases to say,
"I'm only interested in changes
in the radio station
generated by this object."
So that's the sender
there that you would put.
Okay? The method that's
going to get invoked here --
method to invoke if
something happens --
always has one argument,
which is an NSNotification.
Inside an NSNotification
there are three properties:
One is name, that's the
name of the radio station --
same thing that was
passed above; object, okay,
that's the object sending
you this notification,
so that would be the
sender anything above;
and then user info,
which is an ID.
And to know what that is, you
have to know what the person
who broadcasts on the radio
station says they will
provide there.
Does that make sense?
So that user info is
radio station-dependent.
But if you know the name
of the radio station,
you probably are looking in
the documentation to find it,
it probably says there, "Oh,
and the user info you'll
get is X, Y, or Z."
But it's an ID.
So you have to know what it is.
You're probably going to
do is kind of class on it,
or response to selector, or
something like that to use it.
A lot of times that's nil
because all we're
really interested
in is whether there
was a broadcast,
not any particular
information that was broadcast.
Question?
>> About sender is that
global over just your app,
or global over the whole system?
>> All this stuff
-- the question is:
Is the sender there
global to the whole system
or just inside your app?
Always everything
about notifications
inside your app, okay?
Because the space of objects
in the heap is only
inside your app.
You can't see in other apps.
You know, they have
their own segregated
for security reasons space.
So if you're getting a
message here from the system,
this is going to be nil, okay?
The sender's going to be nil.
Question? That was
your question?
All right.
So another thing
to understand is
when you're done
listening, tune out.
Turn your radio off.
Okay? And you do that
by sending a message
to the notification center
saying "remove observer."
And you can remove
yourself as an observer
of all radio stations
with the first one
or you can just remove
yourself from listening
to certain radio stations,
okay, by specifying the name
of the radio station and who
the sender is you don't want
to listen to anymore.
Okay? It's important to do
this because, unfortunately,
the notification center
keeps a pointer to you
that is called "unsafe
retained."
So it's not strong or
weak; it's unsafe retained.
And what unsafe retained
means is that if you go
out of the heap without
calling this first,
the notification
center might try
and send you a notification
and crash your app.
That's why it's unsafe.
Now, why are these
unsafe retained here?
Clearly for backwards
compatibility.
This really should be weak.
Okay? It would be awesome for
this to be a weak pointer to you
because then if you went out
of the heap, it would be set
to nil inside the notification
center; it would never try
and send you any messages.
But, you know, the whole weak
mechanism of setting things
to nil automatically, that's
an iOS 6, iOS 7 only thing.
So if you had an
app that was running
on iOS 5, that wouldn't work.
And if this depended on
that, it would be bad.
I'm sure eventually they would
probably move these things
to weak and just say, "If you
use this API, it's depreciated;
you can't run in iOS 5."
I don't know, maybe they'll
do that in iOS 8 or 9.
I don't know.
But be careful there.
It's unsafe retained.
It's the only unsafe retained
really you're probably going
to have to worry
about in this course.
But the bottom line
is: Remove yourself
when you're done listening.
Now, normally you're
going to remove yourself
when your MVC goes
off screen, okay?
Because you're usually
only interested
in radio station happenings
when your MVC is
active and on screen.
But if for some reason
that doesn't make sense,
there is a method
called "dealloc."
Every object has this.
It gets called just before
your object leaves to the heap.
Okay? All your properties
are nil.
You are barely existing as an
object and this gets called.
Okay? It's that last hook.
And so you can fix unsafe
retained pointers to you there.
Okay? I don't recommend
using dealloc.
Don't use it for anything else,
that's for sure in this class.
I suggest removing,
it would make sense.
Question?
>> How do you remove
yourself as an observer
and you're not an
observer on anything?
>> Great question.
So the question is: What
if I call remove observer
and I'm not observing anything?
No problem.
Nothing bad will happen.
>> So you could just
throw that in dealloc.
>> You could.
You could.
It wouldn't be very
nice programming.
It's kind of not very pretty,
but you could just throw
that in your dealloc to be safe.
But better to, you know -- okay.
So here's an example.
This is an example I'm going
to demo real quick here,
which is text size.
So in iOS 7 -- not in any iOS
before that, but in iOS 7 --
if you use preferred fonts,
then the user can actually go
into settings and change
the size of their font.
So if they're like me and the
phone has to be held farther
and farther away as the years go
by, you can set the text size up
and move that phone
back in a little bit.
So that's what this text
size thing allows you to do.
Well, if that text size
font change happens,
you have to get notified so
that you can change the fonts,
use the new preferred font
that the user set, okay?
So you get that notification by
signing up in the default center
for the radio station called
UI content size category did
change notification.
Okay? You could argue
it could be something
like preferred fonts change.
But it's not.
UI contents size category did
change notification, okay?
You sign up for that,
and whenever those fonts
change size, your method --
"preferred font size change"
is what I called mine --
will get called.
Okay? So let's take a
look at how we would add
that to attributer because
attributer uses preferred fonts.
And if we change the font
size, we want the body
and the headline both to change
to the bigger or smaller font.
So let's do that.
I'm going to go back
here to Xcode.
So here we are.
The other thing we're
going to need
to make this work is the
view controller lifecycle.
Okay? Because we're only
interested in those font changes
if we're the MVC that's on
screen, which we always are,
of course, because we
only have this one MVC.
But soon we will have other MVCs
and we won't always
be on screen.
So let's use the view controller
lifecycle method viewWillAppear.
Okay? So when a viewWillAppear
--
notice I'm always going
to do super there.
You can call super before
or after you do your work.
It kind of depends
on what you want.
Do you want your super
class to get a chance
after you've done what
you want to do or before?
Usually it doesn't
matter too much.
I don't know that UI view
controller actually does things
in these supers,
but you always want
to give them the
opportunity, okay?
It's just part of the
view controller lifecycle.
So when the view appears,
I just want to sign
up with the notification center
so that I can receive
these messages.
So I'm going to say
"Is NS notification center
default center add observer
self," okay?
I want these messages
sent to myself.
The selector, remember we
have to say "at sign selector"
when we want to specify a thing.
I'm going to call it
"preferred fonts changed."
Okay? Name is UI
content size category --
lucky, I get to tab
through that one.
Okay? And the object is nil.
In other words, if
anybody sends that,
I'm going to change
my preferred fonts.
Okay? Notice there's
a warning here,
that's because I
don't implement this.
I believe that's new in iOS 7.
I don't remember
seeing that before.
Okay. Thank you.
Too many Rs.
Okay. View -- void
here preferred.
Oops. Two Fs now.
Okay, preferred fonts changed
takes an NS notification star,
okay?
Notification, I'm
not going to use
that because it's just
basically Boolean.
And I'm actually going
to call another method.
I'm going to call use preferred
fonts, and you're going
to see why here in a second.
Okay? So that set it up so
that anytime my view appears,
I'm going to get this
use preferred fonts sent
to me -- preferred fonts sent.
And in here I have
to make my text view
and my headline use the
new preferred fonts.
And that's really,
really easy to do.
Self.body.font equals UI font
preferred for text style.
UI font text style
-- this is the body,
so I'm going to do body.
So this has allowed me
an excuse to show you how
to set these preferred
fonts in code instead
of setting them in Xcode.
This is how easy it is.
Okay? Now I'm setting the
font of the UI text view.
So if I had any bolds
or italics,
unfortunately this
would blast them.
So obviously, I would
need to iterate
through all the attributes
and look at the font,
get the symbolic traits,
apply them like I
talked about earlier.
And then let's do the same
thing for the headline,
but its font wants to
be the preferred font
for headline, which is this one.
Okay? So that's that.
One last thing to consider here
is I need to stop listening --
we'll do it in will disappear.
Could do it in either
but -- okay.
When I'm going to disappear
I want to stop listening.
And so, again, NS
notification center,
default center, remove observer.
Now, some would argue
just putting self here,
but I actually think that's
bad coding because, you know,
what happens if you add a
new feature down the road
where you're listening on
a different radio station
that you don't want
to stop listening
to when your view disappears?
Which is rare, but
it's possible.
So I actually think it's better
here to use the version of this,
which remove observer
that takes the name.
So I'm going to say
remove yourself name is UI
content blah-blah-blah.
And the object is still nil.
So I'm only going to
remove myself as a listener
from that one radio station.
And there's one last thing to
do here, which is what happens
if my view appears, I start
listening, it disappears,
and then they go
change the text style?
And then I reappear?
Okay? I will not be notified at
that point because the change --
the text style change --
happened while I
wasn't listening.
So turning your listening
back on,
you don't get all the messages
that happened while
you weren't listening;
you only get new messages.
So that's why we probably want
to say self use preferred
fonts in viewWillAppear.
This is why I'm talking about
where viewWillAppear wants
to sync up with the
world when it starts.
That's what viewWillAppear
is for.
So viewWillAppear is going
to use preferred fonts,
whatever are currently
out there.
Okay? That make sense
why I'm doing that?
So let's run this
and see if it works.
Now, I'm running
this on a device
but on your simulator you
can also go to the settings.
So here's my text, right?
So let's even go ahead and
put some orange text in there.
Okay. Now I'm going to hit the
home button and I'm going to go
to settings, which
is right here.
I'm going to go down to
general, I believe it is.
Is that it?
Yeah, text size.
You see text size right there?
You can see there's a slider.
So let's make our
text really big, okay?
Go back. I can just
go back to here.
It's still running
in the simulator.
Okay? So if I had
breakpoints and stuff,
that would all still work.
And now I can see
my font is big.
I kept my orange right there.
You can do this.
I can put an outline on there.
Green maybe.
Okay, you can see the outline
a little better with green.
And now if I go back
again to settings --
and let's set this all the
way to small and go back.
Back to our thing, you
can see it updates it.
Okay? So make sense?
Everyone understand
what's going on there?
Okay. So there you can see
in that part we used --
we showed you how to do the
preferred fonts in code,
and we also used notification
center to do the radio station,
and we also used some more of
the view controller lifecycle.
So that was multihit there.
And so next time -- what's
coming up on Wednesday --
we're going to take
this app and we're going
to add some more view
controllers to it.
So multiple view controllers.
Now, it's very important
to pay attention for that
for your assignment because
that's the fundamental thing
we're asking you to do in the
assignment that's going to go
out on Wednesday is
make multiple MVCs --
it's still going to be Machismo
but you're going to have
to do another game,
have both on screen,
have yet another thing
appearing on screen.
So you're going to
have at least three
and if you do extra credit,
four or five different MVCs.
So we're going to rapidly start
going up to multiple MVCs.
We're going to talk about how
to add MVCs with the tab bar
and also navigation controller.
That's the first two ways we're
going to learn how to do that.
Really important to understand
for Wednesday is we're going
to use inheritance because two
of your MVCs are going
to be very similar.
They're both going to be
card games, but they're going
to be a little different.
You're going to want
to use inheritance
to share a code between them.
So I'm going to kind of get you
started on that on Wednesday.
And so I'll be sending out
assignment three on Wednesday.
Friday we were going to be doing
getting your device working
with the free university
developer program; however,
that's not working
technically right now.
So we're going to put
that off until next week.
So next Friday -- not
this week's Friday,
but next Friday -- we'll
be having a section
where you can come
to the section
and we'll help you get it so
it's working on your device.
>> For more, please
visit us at Stanford.edu.
