>> Stanford University.
[ Pause ]
>> All right.
Well, welcome to lecture four,
then, of CS 193P for fall
of 2013/14 -- academic
year 2013/14.
Today I'm going to do
pretty much all slides.
I do have one brief time when
we'll stop and do a little demo.
And then at the beginning
of next lecture,
I'll be doing a demo that pretty
much demonstrates the vast
majority of what I talk
about in the slides today.
And remember, that's kind of
how it's always going to go:
I'll show it to you in
slides, we'll talk about it,
then I'll demo it to you.
Because when you see a demo,
it all makes a lot more sense
than if someone's just talking
in an abstract conceptually
about an API.
And then your homework
is usually going
to ask you to do this.
So it's, you know, you get a
lot out of paying attention
in the lectures because
I'm pretty much going
to give you hints and
basically tell you a lot of how
to do the homework -- at
least from the iOS side of it.
I'm still going to ask you to
do the thinking side of it,
the designing side of it.
So today we're going
to start off by talking
about a little bit more
miscellaneous Objective-C.
And then I'm going to go into
talking about Foundation,
which is this framework
that has arrays,
and dictionaries,
and all that in it.
And we'll start to transition
out of Foundation at the end
of that and start talking about
things like fonts and colors,
which are obviously
not in Foundation
because Foundation is
really not a UI-based thing;
it's for building
both your model,
and your controller,
and your view.
But it's, you know, a layer
below the user interface layer.
So let's dive right in.
Let's talk about
creating objects.
A few of these things are pretty
obvious I hope, but I just want
to put them on slides so that
you have them in writing here.
You know that most of the
time when we create objects
in the heap, we do it with this
alloc init business, right?
So sometimes the
init is just init
like NSMutableArray alloc init,
and sometimes it's more
complicated init like we had
with our card matching game --
init with card count using deck
-- so that you're used to that.
And you've also seen
us create objects
in the heap using class
methods like string with format.
Remember, we did NSString,
string with format.
And that's a class
method, right?
Because it's open square
bracket, name of a class,
and then class method.
So it gets kind of two different
ways you've seen already
to create objects.
Sometimes for some methods,
there's both an init
and a class method.
So string with format is an
example that there's alloc init
with format and there's
NSString, string with format.
They do exactly the same thing.
Both of them are there for
kind of historical reasons.
Back before we had this
automatic reference counting --
you know, the strong
and weak thing --
you had to be much more
explicit about things
when you were going to,
you know, reference them,
and when they got dereferenced,
and when you cleared them
out of the heap,
and all that stuff.
And one of the ways that was
done was using these class
methods to create
the string in a way
that it would get
released in certain ways.
So all of that doesn't
matter anymore.
So now we're kind of stuck with
having both of these things.
It seems to me that iOS,
the designers at Apple --
I don't work at Apple,
by the way.
Some people have asked
me if I work at Apple;
I don't work at Apple.
So I'm just seeing iOS from
the outside just like you are.
It looks to me like iOS people
are moving towards alloc init,
okay, and kind of away
from the class methods.
Although I still see
the class methods coming
up in certain circumstances,
too.
And there's probably
some reasoning behind it.
I haven't seen it put in
writing by Apple as to
when they choose which,
but you're certainly safe
in this class until they start
marketing some of these things
as deprecated, like,
don't use them anymore,
to use either form, okay?
I tend to try to go for the
alloc inits most of the time,
unless there isn't an alloc
init that does what I want;
then I'll use a class method.
But there's other ways
to create objects.
Okay? You can create objects
by asking another object
to create an object for you.
So that's like string
by appending string.
That's not a class
method in string;
that's an instance method.
You send it to another string,
you give it a second string,
and it will create
a new string for you
since strings are immutable.
NSString is immutable.
It creates a new string that
is the string you sent it
to with the one you passed as
an argument added on, right?
So there it's creating a
new object for you, okay?
And a very interesting
instance method
that you can ask an object to do
for you is mutable copy, okay?
So mutable copy makes a copy
of an object but it's mutable.
So if you had an NSString
and you send it mutable copy,
you'll get back an
NSMutableString.
Or if you have an NSArray and
you send it a mutable copy,
you'll get an NSMutableArray.
So that's another
way that that happens
that you're creating objects.
Of course, not all methods
that return an object are
creating an object like we saw
in NSArray -- last
object, and first object,
and object date index.
Those aren't creating
new objects;
they're just giving you
pointers to the objects
that are in those array.
Okay? That should be completely
obvious to you but just want
to make it clear, you know,
these are pointers to objects.
And you're allowed to
have multiple pointers.
And this is normal pointers
here being passed around.
Okay? So basically, unless
a method has the word "copy"
in it, then if it's
returning to you an object
that exists somewhere else, it's
going to be returning a pointer
to that object, okay, unless it
has the word "copy" in it like
"mutable copy" or "copy."
And if the object that you're
getting back doesn't exist
somewhere, then it's going
to make a new one for you.
All right.
That's it on creating objects.
Pretty straightforward there.
Okay. Nil, I already
talked about this,
that we can send messages
through a pointer that is nil,
i.e. that pointer does
not point to anything.
And no code gets executed.
So if I do this init
I equals obj method
which returns an init, no code
gets executed to execute method
which returns an init; however,
that message sending square
bracket thing will return zero.
Okay? So that's important
to know.
And zero is also what nil is.
So if you had a method that
returned an object and you sent
that message to nil,
then you get back nil.
Okay? And we can use that,
actually, to our advantage.
For example, in our
thing we did on Monday,
we did draw a random
card, right?
Self.deck draw a random card.
And that returned nil if
the deck was out of cards.
Okay? If the deck
itself had been nil,
that also would return nil.
So we can write one if
that deals with the fact
that we can't get
another card, whether it's
because the deck is empty
or because there is no deck
because the deck is nil.
Either way, the code's going
to look exactly the same.
Okay? So you'll get
used to that.
It's definitely different
from other languages
where you're protecting
against sending messages to nil.
But you'll get used to it.
You do have to be careful.
If the return type of a
message send is a struct
because you don't get back a
struct with all its members set
to zero; you get back
an undefined struct.
Okay? What's in there
is undefined.
Okay? This struct is being
returned to you on the stack.
You might get stack garbage,
you might get zero.struct,
you just don't know.
So you can't rely on it.
So here you should never
rely on that in your code.
Okay? If you call a
method, it returns a struct,
you got to check to make sure
you're not sending it to nil.
Okay? All right.
Dynamic binding.
So Objective-C handles the
dispatching and calling
of methods differently
than languages
that most of you are used to.
It does what's called
"dynamic binding."
Okay? And you'll see
what dynamic binding is
as we go through this slide.
But the important thing to
understand about dynamic binding
and about Objective-C is
that there's a really,
really important type in
Objective-C called "ID," okay?
We call it "ID."
We don't call it id by
the way; ID we call it.
So here in that line of code I
would say that's ID my object.
Okay? So I'm declaring
a pointer,
my object, which is a type ID.
So ID means pointer
-- ID is a pointer,
so we don't use ID
star; ID is a pointer --
it means a pointer to an object
where I don't know its class.
Okay? Of unknown type or
unspecified type, okay?
So it's just a pointer
to an object;
I do not know anything
about that object.
Really, all pointers
in Objective-C are IDs
in that the decision
about what code to execute
when you send a message to
an object is not determined
until runtime when
you send that message.
Okay? When you send a message,
it's essentially calling
a function that's looking
up the right code to execute
for that particular class
that you're pointing to at the
time you send the message, okay?
That's called dynamic
or late binding, okay?
And all message sends -- all
of them in Objective-C --
are done this way, okay?
Now, what does this mean?
All right?
It means that -- well,
is this safe, right?
Because you're worried, I'm
sure, "What if I send a message
to an object and it
doesn't understand it?"
Okay. Well, nothing stops
you from doing that.
And not only that, if you do
that, your program will crash.
Okay? It will raise
an exception.
Unless you catch the
exception, it will crash.
And so you're probably
feeling like, "Wow.
These Objective-C programs
must be crashing all the time
because you accidentally
send a message to an object;
it doesn't understand
that message."
But actually, it doesn't happen.
Okay. Why doesn't that happen?
And there's really two reasons.
One is we use static
typing a lot.
We don't use ID that much.
We use, like, NSString star.
Now, NSString star is
exactly the same as using ID,
except that the compiler,
while it's compiling your code,
knows that you at least intend
that that pointer
points to a string.
So if you tried to send
a nonstring message
to that pointer, it's
going to complain.
It's going to, you
know, give you warnings.
And so when you compile your
Objective-C programs they should
always have no warnings, and
then you can be pretty sure
that you're not going
to have this problem
where you send a message
to an object at runtime
and it doesn't understand
it and it crashes.
Okay? So that's the
number one way.
And the second way I'm going
to talk about is that a lot
of times we will
check at runtime.
We'll look at that
ID pointer, okay?
And we will check and
see if it responds
to something before we send it.
Okay? So you know
about static typing,
that's the NSString
star S equals
at sign X. This is really safe,
really good, nothing bad's going
to happen here because
the compiler
at compile time has a pretty
good idea what you intend
and it will warn you if not.
However, the compiler
is not doing the binding
between what codes
executes at this time;
it's just warning you.
It's syntactic sugar.
Okay? It's syntax that it
can look at to warn you,
but it's not actually
enforcing anything here.
It's perfectly legal
to say ID obj equals S,
where S is the line before.
Okay? And that will not
even generate a warning.
Because ID obj is a pointer
to any kind of object;
S is a pointer to
any kind of object.
It's a pointer to a string,
according to the previous line.
But since those are both
pointers to objects,
that's perfectly legal.
Compiler will not warn you.
This is a little bit of a
dangerous line of code, right?
Because you just
went from having S --
this nice variable that's typed
and the compiler can warn you
if you do the wrong thing
-- to having an obj,
which is this untyped pointer
where you can send
any message you want
and the compiler's
not going to warn you.
Okay? You can also do this
NSArray star A equals obj.
Okay. Now you have
NSArray variable
that points to a string.
Now, that's extremely likely
to cause a problem, okay?
This is also legal because
NSArray star A is a pointer
to an object; obj is a
pointer to an object,
so it allows this assignment.
Very dangerous.
Obviously wrong.
If these three lines of code
are there, that's clearly wrong.
You would not want to have an
NSArray pointing to an NSString.
Okay? So ID can be
dangerous in this way.
And in fact, in the code
that we've written we already
did this kind of silently.
Remember that in playing cards
match we put a line in there
that said, "Playing card star
other car equals other card's
first object."
Remember that?
Well, the method first object
in an NSArray returns an ID.
If you go look it up
in the documentation,
look at its return
type -- parenthesis ID.
Okay? So we just assigned
a playing card to an ID.
So that object that came out of
that array better
be a playing card
or we're going to
crash at runtime.
And a little later in
this lecture I'm going
to show you how we can
protect our code to make sure
that we don't crash
in this case.
Okay? Does everyone see why
this is a little dangerous?
All right.
Questions about that?
Okay. And a reminder:
Never use ID star.
ID star makes no sense
because ID is a pointer.
So ID star would be a
pointer to a pointer.
We don't do that in
Objective-C, okay,
especially a pointer
to an ID [inaudible].
All right.
So to summarize all this I'm
going to show you this example.
I've got two classes:
I got a vehicle class,
which has what method move --
you can move the
vehicle around --
and I got a ship which is a
vehicle, inherits from vehicle,
and it's only got
one method, shoot.
So this ship can
shoot other ships.
And they can also move
because they're vehicles.
Okay? So if I declare a
local variable ship, ship S,
which is a ship star, and
I allocate init a ship,
I can say "S shoot" or "S
move" -- works fine, right?
Because ships implement
shoot and they inherit move.
So everybody's totally
happy here.
I can also do vehicle star V
equals S. That's perfectly legal
because V is a vehicle
and S is a vehicle
because it inherits its
vehicle-ness from ship.
Okay. This is like deck equals
playing card deck alloc init --
perfectly legal object to run
in your programming, right?
Okay. But now let's try
to say V shoot, okay?
Now, what's going
to happen here?
All right.
At compile time you're
going to get a warning
because vehicles do
not implement shoot;
ships do but not vehicles.
So do you see why this is
going to give you a warning?
Okay? What about at runtime?
This code will not
crash because we know
that V actually is a ship.
So this will work
fine at runtime.
Okay? See that?
So this is where
you get a warning
at compile time;
runs fine at runtime.
Okay? Now, what about this case
where I declare an obj, okay,
and it can be anything we want.
Okay? Alloc init it somehow
and you say "obj shoot," okay?
No matter what obj is --
and I intentionally
didn't tell you what obj is
because it doesn't
matter what obj is.
The compiler is not
going to warn you here.
Anytime you send
a message to obj,
as long as that message
exists somewhere,
the compiler will not warn you.
Okay? At runtime, if obj is
not a ship or some other object
that responds to
shoot, it will crash.
Question?
>> Is ID special in that way?
>> In what way?
>> Because it seems
like it's a similar case
where whatever you've assigned
obj is a pointer to an object
but it may or may
not have this method.
>> Well, so the question is:
Is ID special in that way?
You mean is ID special in that
I can send it any message I want
and the compiler won't warn me?
Yes. Because that's kind
of the semantics of ID.
ID means a pointer to some
object I don't know the
class of.
So there's no way for the
compiler to give you a warning.
So it just assumes "Okay,
somebody responds to shoot.
So it might be this one, so
I'm not going to warn you."
So yeah, ID is special
in that way, I guess.
That's why we don't want to
use ID unadorned like this.
If I'd say obj some method name
that doesn't exist,
then it will warn me.
Okay? So if it can't find
that method anywhere,
no object that the compiler's
ever heard of implements
that method, then it
will at least warn you.
Because then it's likely
you had a syntax error.
You mistyped it.
Okay? And so the compiler
is going to help you there.
So let's say I had an
NSString star hello.
Okay? And I'm going to make
it equal to at sign hello.
If I say hello shoot, the
compiler's obviously going
to warn me and say, "Strings
don't respond to shoot."
And at runtime this would
crash because, of course,
strings don't respond to shoot.
Okay, so this is all good.
This is the way we want things.
What if I did this, ship star
hello ship equals cast --
okay, everyone knows
about casting, right,
all languages have
casting pretty much; well,
most languages that you know --
parenthesis ship
star hello, okay?
This is perfectly legal.
And the compiler will
not warn me, okay?
So I've now taken a string and
put it in a ship star pointer.
And the compiler now thinks
that that hello ship is a ship.
And so it's only going to
complain if you do things to it
that don't look like ship,
even though we know we know
that that is a string.
Okay. So casting can
be super dangerous,
just like in any language
casting can be dangerous.
It can be dangerous here.
But we do do cast sometimes.
And the times we cast are the
same kind of times we use ID,
which is protected times.
I'm going talk about that
protection on the next slide.
So if we then said
hello ship shoot, okay,
that would not generate
a compiling error
because hello ship is a ship
star; however, it would crash
at runtime because strings
don't respond to shoot.
Everybody cool?
Yeah?
>> [Inaudible]
>> Okay, the typecasting
really doesn't do anything;
that is just tricking
the compiler.
Okay? That's not even executing
really any code per se.
It's when you send the shoot,
it tries to dispatch that shoot
to that variable, that
hello ship variable.
The thing turns out
to be a string,
and it crashes right there.
You can also do this:
ID hello shoot.
Okay? So hello is the
NSString star, and I casted it
to ID and sent it shoot.
And that will suppress
all warnings as well
because now I'm sending
shoot to an ID.
And I just want to show you
here that you can cast it right
in line; you don't have to
create another variable.
If you cast it right in line,
you fake out the compiler.
Now, we don't want to be
faking out the compiler.
Compiler is our friend.
It helps us find bugs, okay?
But this all can be done.
Okay? Mostly I put this up
here to see the difference
between the compiler catching
something and it crashing
at runtime, okay, and
when it does which.
All right.
So when would we ever use this
ridiculously dangerous thing
of ID?
Well, someone asked earlier,
"Can I have an NSArray
that has different
kinds of things in it --
some strings, some
numbers, something else?"
Absolutely you can.
And there's plenty of times when
you absolutely want that, okay?
So it's great for that.
Now, other language like Java
lets you actually tell the
compiler that this
array has strings in it
so that the compiler,
when you pull objects out,
it knows what type they are and
it can kind of help you out.
Objective-C doesn't have that.
So the compiler cannot help
you with contents array.
Okay? So it's kind of
your responsibility.
I'm going to show you
how we deal with that.
The second one is --
remember the NBC talk?
I talked about all this blind
structured communication, right,
this blind communication.
Well, to have blind
communication you got
to have pointers to objects
of types you don't know.
Okay? There's no way that the
view can send the target action
thing to the controller
without knowing the class
of the controller, unless
the view can have some kind
of pointer to a controller that
it doesn't know the type of.
Okay? And that's big use of ID.
However, we need to
protect ourselves,
and there's two big ways that we
protect ourselves against IDs.
One is introspection,
which I'm going to talk
about in the next few slides,
which is we can ask an ID
at runtime, "What
class are you?"
or "What methods
do you respond to?"
So that's a great way
to protect ourselves.
And then another way
is called "protocols."
And protocols is a way
using little angle brackets
after an ID to say,
"This is an ID,
a pointer to some class I don't
know what it is, but it responds
to this set of methods
that I'm going to define
with this little
angle bracket thing
like UI scroll view delegate."
And that's how we
do the delegation
and data source thing.
So we're not going to
talk about protocols today
because you don't
quite need them.
We'll probably talk about them
next week or the week after.
But that's another way we
protect ourselves against ID
by having like -- an ID with
the angle brackets is kind of in
between pure ID and
static typing.
It's kind of in the
middle, right?
Instead of static
typing the type,
we're just static
typing the messages
that the thing can respond to.
Okay? So it's kind of in the
middle in terms of safety.
All right?
So let's talk about
introspection, though.
There's a few introspection
methods in NSObject.
I'm going to talk about
three of them here.
Is kind of class, is member of
class, and responds to selector.
So is kind of class
and is member
of class lets you ask
an NSObject or anything
that inherits from NSObject,
"Are you of this kind of class?
Or is member of class means,
"Are you actually this class?"
Not this class or something
that inherits from it,
but actually this actual class.
And then response to selector
says, "Does this object
that this ID points to, does it
respond to a certain method?"
Okay? So the arguments
unfortunately
to these methods are
really kind of wonky.
And just you're going to
have to take my word for it
on these ones because when
I spit out the sentence
in a second here that
describes what the argument is,
I'm going to use the
word "class" four times
and it's going to mean
four different things.
Okay? So the argument
is kind of class,
you get by sending the class
method class to the class,
which will give you a capital
C Class, which is the argument
to the is kind of class method.
Okay? So there's
this method class.
You see it there,
NSString class.
It's a class method on NSString
returns a capital C Class.
And that's the thing that's
the argument is kind of class.
It's always of this form,
obj is kind of class,
open spare bracket, the
class you want, class,
close square bracket,
closed square bracket.
Okay? So it always
looks like this.
So just do it.
If you didn't understand
my four-class sentence,
just do it just like this, okay?
Once I see that an
object kind of a class,
then I might want to cast it.
You see here I'm casting obj
to be an NSString star there
because I know at that
point it's an NSString star.
So it's okay to fool
the compiler,
or really I'm teaching the
compiler a little bit more
about what obj is by doing that.
Not really tricking it.
And it's perfectly safe to do
that because I know that obj
at runtime is that
kind of class.
Okay? Questions about that?
Yeah?
>> [Inaudible]
>> Okay, the question is:
What does the instance method
class -- so I can say, you know,
trying to think of an example
where we use that, like deck.
I might say deck
class, for example.
That returns essentially
the same thing as here,
and you probably
could say is kind
of class open square bracket
instance [inaudible] class.
But your reader would pretty
darn confused by that.
So there's an instance
method and a class method;
probably both return
the same thing,
capital C class, I believe.
But we would never do that here,
so don't put an instance
call there,
just the class method you want.
Good question.
All right.
How about the selector
one, the method one rather?
Okay. So methods, when we
use them in this response
to selector thing, we
call them "selectors."
A selector is really kind of
an identifier for a method name
because if you have
the method shoot,
it's the same selector no
matter what class you're talking
about implementing it in.
Even if they don't
inherit from each other,
they're completely unrelated.
You might have a gun
class that says shoot
and you might have a ship
class that says shoot --
the selector shoot
would be the same.
And we get that selector
by saying
at sign selector parenthesis,
the name of the method, okay?
Shoot. And if the method
has multiple arguments,
we just put the colons in there.
So shoot at colon
has one argument
or add card colon at top colon.
We just say that, at sign
selector, open parenthesis,
add card colon, add top
colon, close parenthesis.
Okay? And that gives
us the selector,
and we say responds to selector.
And that will tell
us whether the object
that we're sending
responds to selector
to responds to that method.
Okay? Now, these selectors,
there's actually a type,
kind of a type def in
Objective-C for these selectors.
All caps SEL, kind of
like all caps BOOL, right?
So this type def thing is added.
And you can declare
variables that are of type SEL
and store things in there.
And there are actually other
methods besides respond
to selector that
take a selector.
For example, object
has perform selector
and perform selector
with object, okay?
They will perform that
method on another object.
Now, why would you
ever want to do this?
Well, you might have
some parameterized thing
where you're going to do one
of three different methods,
depending on something
the user chooses.
And you can say perform selector
and then have three SEL
variables, one for each method,
and pass that as the argument
you want to perform selected.
Perform selected with object,
that method would
have one argument.
So the selector name
better be something colon
because it's got one argument.
And the argument
has to be an object.
So coordinate here would
be some sort of object.
Okay? So just a little
limitation.
It can only have no arguments
or have one argument
that's an object.
You can also do cool things
like ask an array
make all the objects
in yourself perform
this selector.
This is a very cool method.
And if you get used to using
methods like this in Array,
you'll find your
code will shrink
down really small because,
you know, for ins and things
like you have to really
zoomed down to one-liners,
make object perform
selector, okay,
or make object perform
selector with object.
So that's an NSArray thing.
And of course, we do target
action with selectors.
The method, if you wanted
to set up target action,
not doing control drag but
actually setting up in code,
is in UI control actually,
which button inheritance from.
Add target colon, action colon.
There's some other arguments.
But you can see that
add target takes an ID
and then it takes an action
colon, takes a selector.
So it says what message
to send to what object --
what's the target,
what's the action?
Everyone understand that?
Okay. So this selection stuff,
pretty selector stuff
is pretty powerful.
All right.
So let's take a look
at how match --
the playing card match -- might
be improved with introspection.
I'm going to go here
back to Xcode.
And I'm just going to
open back up Machismo
where we left off here.
[ Pause ]
Okay. And then let's go
down to playing card.
So here's playing
card and here's match.
Okay. So you all remember match.
And here's the line of code
that's a little bit of trouble.
Okay? Because this first object
here, this returns an ID.
So what we could do
here, for example,
is we could say ID
card equals this.
Okay? Just to be
totally clear here.
So we got this card.
And then I can say if
card is kind of class,
playing card class, okay,
then I'll do all this.
Okay? All right?
And I'm going to set
the other card here
to be playing card, star card.
So I'm going to cast it.
So now the compiler knows
about this variable.
And from here on out,
whenever I touch other card,
it knows it's going
to be a playing card.
And here I've checked
at runtime to make sure
that it's actually
the playing card
so that I'll never crash here.
Now, if you say match
colon other cards
and the other cards are
like, some not playing cards,
they're regular cards
or they're strings
or something, then that's okay.
This method's going to work
fine because it's going
to return zero, a score
of zero, which is right
because a playing card
wouldn't match a string
or any other kind of card.
Okay? Make sense?
See how we used introspection
there?
So you will have to use
introspection most likely
in your solution to
next week's homework --
not the one you're
currently working on.
By the way, I should take
time out to say I'd almost --
if I ever show you
something in a lecture
after I've assigned something
to you, you almost never need it
in that week's homework.
And I would tell you
if that were the case.
Okay? You know what I'm saying?
So, like, you've got an
assignment on Monday;
I wouldn't be showing you
things today that you needed
for the assignment on Monday.
I've already shown you
everything you need
by the time you get [inaudible].
Okay? Question?
>> [Inaudible]
>> Okay. So the question is:
Is introspection only used
like this when you're
pulling items out of Array?
And remember, I told you a
couple slides ago there are two
major times when we use
introspection -- one is this.
Okay? Second one is all that
MVC blind communication, right?
Target action, and
delegation, and all that stuff.
Okay? So that's that.
Now let's move onto Foundation.
Okay? So we're going to talk
about a Foundation
framework here.
I'm going to really go
fast through object, Array,
dictionary, things like that
because we've already
seen a lot of Array.
I think you pretty much got
a good feel for what it is.
So I don't want to waste
the time talking about that.
We got a lot more new
stuff to talk about.
But you know that NSObject is
the base class for all objects.
It implements those
introspection things.
It also implements this
very important method
called description.
Okay? So description, it
just returns an NSString.
And it's supposed
to return a string
that describes this object.
Okay? When do we ever use this?
Two places.
One, NS log.
When we're debugging, we like
to NS log percent at sign.
And when we do percent at sign,
the matching objects
get sent description,
and that's what gets sent out.
Now, NSString implements a
description by returning self.
Okay? NSObject implements
description very badly.
It returns like the pointer,
a string with the pointer
in it or something.
Description becomes valuable
when you implement it
in your own classes.
So you could imagine
implementing in playing card,
or even in card you could
implement description
that would return self.contents.
Right? And then in the
debugger there's a way --
in which you'll see
this Friday's section --
there's a way to print an
object in the debugger.
It will call description
for you and return it.
So for card you'd
see the contents.
So that's really cool.
And the string shows
you the string.
Arrays and dictionaries
implement description to print
out the contents of the array.
So description's a really
cool little function
to know about in NSObject.
NSObject kind of implements
this framework for copying,
but it doesn't actually
implement copy immutable copy.
If you look in NSObject,
you'll see that these
methods are implemented there
or there's a protocol
for them there.
Copy and mutable copy are --
the semantics of them
vary from class to class.
So it's up the class
to implement it, okay?
Don't be fooled by
the fact that copy
and mutable copy
are in NSObject.
You can't just send copy to
any object and it will copy it.
But NSArray, for example,
NSDictionary, these things,
they implement copy
and mutable copy,
and they do the right thing.
One thing to note about
copy is if you send copy
to a mutable object
like a mutable array,
you don't get a mutable
array back,
even though you just
copied a mutable array.
You get an immutable
array back, okay?
The semantics copy are,
"Give me an immutable copy
of this object back
if possible."
Okay? The semantics
of mutable copy are,
"Give me a mutable
copy of this thing."
No matter whether the receiver
is mutable or immutable,
mutable copy means
give me a mutable copy;
copy means give me
an immutable copy.
Okay? Understand that?
And again, certain
classes implement this;
NSObject really does not.
You would have to implement
it yourself if you wanted
to have your objects
be copyable,
which is pretty rare by the way.
Really not generally doing that.
Okay. NSArray is an ordered
collection of objects.
It's immutable.
When you create an NSArray,
whatever objects are in it
when you create it,
those are the objects
that will be in there for life.
You can't remove any,
you can't add any.
All objects in an array are
held onto strongly in the heap.
So as long as that array
itself is in the heap, okay,
as long as someone has a strong
pointer to the array itself,
all the objects that are in
the array will stay in the heap
as well because it has strong
pointers to all of them.
Okay? You usually
create an NSArray
by sometimes calling a class
method or even alloc init.
But usually most commonly we do
that at sign square
bracket thing,
like how we created
rank strings.
Remember rank strings in
playing card, at sign,
square bracket, and
the elements?
That's usually how
we create arrays.
Sometimes we'll create
arrays by asking other arrays
to add an object to themselves
and give us a new array
since they can't be mutated;
they have to make a new
one and give it back.
So that's another way.
And you know the
basic, you know,
get the count, object at index.
There's a lot of other really
cool methods in an array.
You really should familiarize
yourself with this class.
Okay. It's a lot of stuff.
We talked about make
objects perform.
There's sorted array
using selector.
So you give it a selector
that takes another --
that basically gets sent
to each object in the array
and takes one of
the other objects
in the array as an argument.
So you got to make sure
they have the right type
of argument there.
And it will just use that
to create a sorted version
of the array and give you back
a new array that's sorted.
Okay. So one line of code as
long as you have a selector
for a method that can
compare two objects that are
in an array, you can sort it.
Okay? So you really should
know about all these kind
of whacky things in NSArray.
Now, NSArray can't be modified.
Sometimes that's a limitation --
not as often as you might think.
But there's a mutable
version of Array, of course,
called NSMutableArray,
which we've also used.
We usually create
it using alloc init
or sometimes we use Array
with capacity, okay?
Array with capacity is --
that capacity argument
is just performance hint.
Okay? It's not saying that
the array starts out with
that many items; it just means,
"I think this array is going
to have a hundred things in it."
So creating an array
with a hundred --
it's a performance hint only.
You know that NSMutableArray
inherits everything
from NSArray, of course,
and then it adds add object,
insert object data,
move object at index.
And you know that you can use
the square brackets notation,
right, like self.cards
open square bracket, index,
closed square brackets to
both put things into an array
and get things out of an array.
Okay? And using that notation
is really just calling object
at subscripted index and set
object at subscripted index.
Okay. It's just calling those
methods; that's all it's doing.
But it looks really
nice in your code
to use those square brackets.
Okay? Enumeration, we saw how
to do this for in business.
Don't forget that
that control variable
like NSString star
string in my array --
you see the NSString
star string --
that's essentially
your casting, okay?
Your casting, whatever comes out
of that array to be an NSString.
You're telling the
compiler, "I know that what's
in that array is strings."
Now, if you don't know what's
in there, you could say --
or if it's a mixed things --
you would say for
ID obj in my array.
Then the iteration variable will
be an obj and you'll likely want
to use introspection to find
out what the thing you got back
is each time around the loop.
Make sense?
Okay? Next NSNumber.
All right.
NSNumber is a class that is
used to wrap primitive types
like integers, floats, doubles,
Booles, things like that.
And why do you want
to wrap them?
Usually because you want
to put them in Array
or a dictionary, okay?
So you can't put an
int into an array;
you need to have
an NSNumber object.
You can create them with class
methods like number with int --
that's a class number in
a class method NSNumber --
or you can use at
sign parenthesis.
Okay? So we already saw at
sign square bracket for arrays,
there's also at sign
parenthesis, or even just
at sign number if you
want to create a number.
So you could say at sign three.
You could also say at sign 3.2,
and that would create
an NSNumber
that would contain
that primitive type.
If you put the parenthesis,
then you could put things inside
like calls to methods that
return a primitive type,
or e nums, or anything
you want in there --
any expression that evaluates
to a primitive time can be
put inside of parenthesis.
You say at sign parenthesis
and it will create an
NSNumber with the result.
Okay? Everybody understand
that syntax?
Okay. So other languages kind
of have this autoboxing
kind of stuff in there.
NSValue, I'm not going to
talk too much about it.
It's essentially a way
to encapsulate more complicated
types than primitive types,
so structs basically, C structs.
And NSValue knows how to
wrap up a few different kinds
of structs that are in iOS.
And you can go look
at the documentations
to see which ones.
One thing I'm going to give you
a little tip right here, okay,
sometimes a good way
to wrap up a struct is
to turn it into a string.
Then you can put it in
the array as a string.
It's nice because you print
it out in the debugger
and you can see it
really nicely.
And then there's
ways to turn things
from strings back
into C structs.
So there are C functions in iOS
that turn most of the structs
in iOS into strings and
then other C functions
that turn the strings
back into the structs.
So NSValue -- I think most of
the time you can use strings.
It's probably more
efficient to store something
as an NSValue but,
again, don't overoptimize.
Turning into a string
is just as performant
in the case you're using it.
It's nice because it's a string
and it's easy to look at.
Okay? NSData is another
Foundation class,
just a bag of bits.
And we're going to
be using NSDatas.
We'll talk about them
more when we get to that.
But it's just basically
a certain count of bytes,
that's what NSData is.
NSDate is a date, right?
It has some internal
representation.
It's probably the UNIX
representation like the number
of seconds since 1970
or whatever it is.
One thing to think about
with NSDates, if you're going
to put a date in your UI, you
got to know what you're doing.
Okay? Why is that?
That's because dates
vary dramatically all
around the world.
And I'm not just talking
about in French, you know,
the month names are
different, but you know,
the order of whether
the month comes first
or the date comes first varies.
Some places on earth,
some locales don't even use
the same calendar as we use.
Okay? So there is an enormous
amount of infrastructure in iOS
for dealing with this.
Classes like NSCalendar,
and date formatter,
and things like that.
If you're going to
put in your UI,
familiarize yourself
with all of that.
I don't have time to go over it
all in lecture unfortunately.
But you just need to know
that there's something
you need to know.
You can't just say
NSDate description
and put it in the UI, okay?
Dates are a little
bit complicated.
There's NSSet, which a set is
an unword collection of objects,
so the objects are unique.
Okay? So you put the same
objects in there twice,
it only goes in there once.
So sets are what you would
think of in term of sets.
And there's actually an ordered
set, which is like a cross
between the set and an array.
And you can look those up.
You're not going to
need those probably --
well, you might need set.
Set is nice because you can
do things if you have --
set is very good at telling you
whether something's in the set.
Whereas an array, if you had
an array of a thousand things,
the array might have to do
some binary searching or --
well, I guess it can't
even binary search
because it doesn't
know the order.
So it's got to look
around in there.
It's hard for it to find things.
But a set is probably
hashed and high efficiency.
It can tell you if you had a
set of ten thousand objects
and you ask it, "Is
this object in there?"
it could probably tell
you really efficiently.
Okay? So there are some values
sometimes sets versus Array.
Okay. Dictionary.
This is the second most
important collection class
behind Array probably.
It's an immutable
collection of key value pairs.
It's like a hash table.
Okay? All the keys and values
are held onto strongly, okay?
So if they're in there
as a key or a value,
then they're in the heap.
And they stay in there as long
as the dictionary
stays in the heap.
The keys and values,
obviously, are both objects.
We'll talk about what
the key has to do
to be a key in a second here.
You usually create immutable
NSDictionaries using another
at sign syntax called
"at sign curly brace."
Okay. So it's at sign curly
brace, key colon value, comma,
key colon value, comma, key
colon value, end curly brace.
Okay? So this is kind of like
the at sign square brackets
for arrays or the at sign
parenthesis for NSNumbers.
This is NSDictionary's
version of that.
You look up things
inside a dictionary.
You can obviously
do object for key.
That's a nice method for
looking the value up by key.
But you can also use square
brackets that looks kind
of like looking up an array.
So if I had that colors
dictionary that's showing right
there and I had a string that
was either green, or blue,
or red, and I wanted to look
it up, I can just say colors,
open square bracket,
the color string.
And it will look up that string.
It would return nil if
there's no such key in there.
And it will return the
value, the actual UI color.
So we're going to talk about
UI colors in a couple slides.
Okay? So this is also
really cool UI --
or syntax rather --
for accessing stuff.
These at sign square
brackets, at sign curly brace,
at sign parenthesis -- big
improvement to Objective-C.
Of course, you can see
how many objects in there.
You can do object
for key to get it.
Key has to implement
hash and is equal, right?
It's a hash table.
You have to be able
to hash the key
so we can have an
efficient lookup.
But then two things might
hash to the same thing,
so you have to have is equal
determine whether two objects
that hash to the same
thing are actually equal.
NSObject implements
this very poorly, okay?
So you would never use a
generic object or some subclass
of object that you've created.
You would never use it as a key.
You're probably going
to do pointer hashing.
So it would only do it if your
objects are always unique.
In the heap there's never
two objects that are the same
that have different pointers.
Strings are excellent
keys in NSDictionaries.
And so I would say
strings are the key
in a dictionary 90
percent of the time.
Okay? They're very good.
They hash really well.
They're very fast and
do is equal, etc. Okay?
Of course, immutable, again,
we'd like to sometimes add
things to our dictionaries.
So we have a mutable
version, NSMutable dictionary.
Usually create it
with alloc init.
It has all the things
of a dictionary,
plus it has set object for key
-- that adds a key value pair --
and you can remove objects, add
entries from another dictionary,
etc., etc. Looping through a
dictionary looks like this.
You do for ID key
in the dictionary.
So basically when you do
for in on a dictionary,
you're looping through the keys.
Okay? Now, of course,
inside it's really easy.
You just say, "Value
equals object for key,"
or even use the square brackets
notation to get the value.
So you're kind of looping
through the values, too,
as long as your hashing
is efficient,
which it is if they're strings.
This is [inaudible].
It is possible to
ask a dictionary,
"Give me all your
values as an array"?
And then you could for
in through that array.
And whether that's
more efficient
than doing this probably depends
on the size of your dictionary,
etc., etc. Don't worry about it.
It's never going to be
an issue in this class.
We're not going to
have dictionaries
of thousands of objects.
Okay? All right.
Next thing I'm going to talk
about is not a class, or syntax,
or whatever; it's a word,
a phrase -- property list.
Okay? And I'm just going
to define this term.
You need to know what this
term means, property list.
A property list means a
"collection of collections."
Okay? What's a collection?
NSArray, dictionary, even
string, NSData, NSNumber --
those are all simple collections
if you want it think of them
that way or they're the
leaf nodes of collections.
So if you have any object
graph that just has arrays
and dictionaries, numbers,
strings, dates, and datas,
then it's called
a "property list."
So just for an example, if
you had an array of strings,
that's a property list;
an array of arrays,
and those array contain property
lists, it's the property list.
Okay? So any arbitrary graph.
But as soon as you have any
object in there that's not one
of these things or
they're mutable versions --
that's allowed, too; so you
can have NSMutableStrings
or NSMutableArrays in there
-- then it's a property list.
Okay? A dictionary is only a
property list if all of its keys
and all of its values
are property lists.
Okay? So a dictionary
that keys are strings,
and values are arrays, or other
dictionaries of property lists,
that would be a property list.
Why do we define this term?
Because there's a bunch of API
throughout iOS that you're going
to see that takes a property
list as the argument.
But property list is
only a phrase we define,
so it's probably
going to take an ID.
Okay? It's going to take an ID.
It might take an NSArray
or an NSDictionary,
depending on the API.
But it's basically saying in
its documentation, "The argument
to this is a property list."
So even if it's an array,
it's got to be an array
of property lists.
If it's a dictionary, it's
got to be a dictionary
that has only property
lists with keys and values.
If it's an ID, it's got to
be an array, or a dictionary,
or a string, or number.
You know what I mean?
It's got to be a property list.
Okay? Make sense?
And in fact, I'm going to show
you one class that only operates
on property lists,
which is NSUserDefaults.
So NSUserDefaults is this one
shared dictionary essentially
that persists, even across
application launching.
Okay? Exiting and launching.
So it's like a permanent
NSDictionary kind of.
Everything that's stored in
an NSUserDefault database has
to be a property list.
Okay? So it's not a
full-on database, though.
All right?
It's pretty small.
It's not really high
performance.
So you only want to store
small things in there.
Okay. You don't want to be
storing huge images or anything
like that, you know,
turning them into NSDatas
or something and storing them.
You really don't
want to do that.
Small strings, and arrays
of strings, and NSNumbers,
dates maybe -- those
kind of things is okay.
Its API. To access it,
you call this class method
on NSUserDefaults called
"standard user defaults."
And that will give you an
instance that is shared
across your entire application.
It's like a global.
Okay? There's only
one of these things.
And you send messages to it
like this set array for key.
There's also set double for
key, set object for key.
That object would have
to be a property list.
So it's kind of like
a dictionary
but it has these extra method
like set double for key
so that you can store primitive
types in there without having
to turn them into
NSNumbers first.
You know, it kind of
gets the type checking
of versus just set
object for key
where it doesn't know whether
that's a double or not,
etc. And some of this --
because now have the autoboxing,
you know, the at sign
parenthesis business --
some of this API we don't
really need that much anymore.
But it's all still in there.
Yeah?
>> [Inaudible] So in
this property list idea,
does that have to cascade
down through all of its sub?
>> Yeah. So the question is:
Does the property list idea have
to cascade down through
all of the sub things?
And the answer is yes.
A property list, for it
to be a property list,
everything in the entire object
graph has to be a property list.
All the way down.
Okay? No exceptions.
And if you were to, for
example, call set object for key
and you passed it
something that somewhere
down a leaf node
was a card, right,
or some nonproperty list thing,
this method would raise
an exception and say,
"That's not a property
list," okay, at runtime.
So it would crash your program.
The other thing to
remember, though,
is once you've gotten this
standard user default instance
and you've stored what you want,
you have to call this
method synchronize
on the instance, okay?
So NSUserDefault, standard
user default, synchronize.
That's what makes it permanent.
So you write a few things,
a little batch, and
then synchronize.
Okay? Don't forget
to synchronize.
If you were to set
some things in there
and your app crashed before
you did the synchronize,
it would not get synced.
Okay? When your app launched
again it would be gone,
the stuff you put in there.
Okay? The last thing really I'm
going to talk about that's kind
of in the core part of
Foundation is NSRange,
which is just a C struct.
It's exactly what you
think: It describes a range.
This might be a range
in a string
or it could be a
range in an array.
It's basically a
starting location,
that's the NSUInteger
location and a length --
how many characters or how
many items in the array?
There's an important
constant called NSNotFound.
All right?
NSNotFound is the value
of location in a range
that was not found or
that is otherwise invalid.
Okay. So it's, like, search
for a substring in a string
and it couldn't find it, you're
going to get a range back
that the location is
going to be NSNotFound.
Everyone understand that?
There's also this
thing, NSRangePointer.
That's basically
just an NSRange star.
Okay. Now I told you in iOS
we don't really put structs
in the heap and we don't.
This NSRangePointer is for
call by reference ranges.
Okay? So some methods will
take an NSRangePointer
as an argument -- one
of its arguments --
and what it's saying there
is, "If you pass me a pointer
to a range, I'll fill it
in with some information."
Almost always you
can pass null there
and it won't fill
the information
in because you won't
be pointing to a range.
But it's for reference.
Everyone know what it
means to call by reference?
Question?
>> Just out of curiosity,
why are you using unsigned
or why did Apple choose to
use unsigned on its range.
It seems like you
can't represent a range
over negative numbers.
>> Yeah. So the question
is: Why did Apple choose
to make location be
an unsigned integer?
In other words, why can the
range only be a positive range?
And I think the main reason
they did that is, you know,
they designed NSRange
for their own purposes,
like ranges in arrays,
ranges in strings.
They never want to
represent that.
And I will bet you dollars
to doughnuts NSNotFound is
either the maximum integer
or it's minus, you know,
whatever, negative,
which sometimes are
the same thing, right?
If you know how computer
science works,
a lot of times it's all the
bits inverted, that's minus one
that also would be at
the end of the range.
So I think it's just
because they didn't need it
for anything else
and they wanted
to make their API
clearer possibly.
I don't know.
I don't work at Apple
-- never did --
so I don't really know
why they did that.
Okay. So that's really kind of
it for the Foundational stuff.
I am going to talk about some
more classes in Foundation.
But first we're going to
take a little detour and talk
about a couple classes in UIkit.
Okay? And those are
colors and fonts.
All right.
So UIColor, super simple
class, represents a color.
The color can be represented in
so many different ways, RGB --
red, green, blue, right?
HSB, that's hue,
saturation, and brightness.
It could even be a pattern.
Okay. So you can have a color
that is a UI image
pattern in there.
And when you draw
with that color,
it will draw with the pattern.
So color, super powerful
but nice and simple API.
Colors can also have alpha.
Okay. How many people in here
do not know what alpha is?
Never heard the phrase "alpha"?
So everybody knows
what alpha is.
Okay. So that's a first.
So alpha, which in computer
graphics is how transparent it
is -- one being fully opaque and
zero being fully transparent.
You can create colors that
are partially transparent.
And then if you draw
with them, you'll be able
to see behind where
you filled in.
So colors are really cool.
There's a handful of kind
of standard colors --
the green color, red color,
purple color, whatever.
You can look in its
documentation to find those.
They're just class method.
There's also a few methods in
there like the light text color,
which is the shade of
gray for light text,
disabled text, or whatever.
So you can look at all that.
Okay? So colors are simple.
Fonts, not to simple.
Okay? Now, fonts in iOS 7
are incredibly important
to get right.
Okay? A huge percentage of good
iOS 7 UI design is picking the
right fronts, and using fonts in
the right way, arranging fonts
on screen in a nice way.
Super important.
So there's a lot of
support in iOS 7 that's new
that is basically
about making it easy
to do the right thing
with fonts.
So I put up some examples
of some iOS 7 apps here.
And you can see how front
and center fonts are
on all these things.
Okay? If you had ugly fonts
here or you didn't have bold,
or you had, you know, fronts
that were too smashed together
or hard to read or the wrong
color, these UIs would be,
you know, impossible to decipher
or very difficult
to decipher here.
So color, and background
colors, and, you know,
the size of fonts, and all
these things are all critically
important in all of
these applications.
Okay? So we're going to talk
a little bit about how to deal
with this and what's in there
for iOS 7 to make this happen.
Unfortunately, I don't
have enough time in lecture
in general to go
through all of this.
I'll kind of distribute little
bits of wisdom about it as we go
through various UIs in lecture,
and demos, and things like that.
What I'm going to try and give
you today is just the basis
for how we present
text on screen, okay?
What the primitives are
for that and how we do it
in the right way so
that we get consistency.
See, the one thing
about all these apps --
do you see how the bold font,
and the fonts you can click on,
and the kind of little
subheading fonts,
they're all related fonts, same
family -- maybe, maybe not.
But they're related.
They're the same sizes.
They look the same.
So all the apps kind of
have a similar look, okay?
That's because they're
all using fonts properly.
Okay? So let's talk about fonts.
The most important thing to
understand about fonts is
that if you're displaying
user content --
okay, that the user's
information.
So in the calendar that's the
appointments, and the days
of the week, and the
month, and all those things.
In the weather it's the
temperature, and the name
of the city, and
things like that.
In the timer app it's the
city that the clock is in.
So if it's user content --
in other words, it's not
the text on a button, okay?
It's not a text on a button
that user's clicking like edit
or something like that.
Then you want to use
a preferred font,
what's called a "preferred
font."
And so you want this
incredibly important method.
If you only learn one
method in all of UI font,
it's this iOS 7 method called
"preferred font for text style."
Okay? The text style
argument is a string.
You use a constant that
you're going to look
up in UI font descriptor,
actually.
If you go through UI font,
you can link click
through and find it.
And so there's the body style.
So that's text that's in
the body, the main part
of what's being displayed.
So like, in an appointment
that would be --
like in a calendar item that
would be the actual information
about what's going to
happen at that appointment.
And then there's
a headline style.
So that would be,
obviously, a header.
There's footnotes,
captions, like a caption
on an image, things like that.
There's about, I think,
eight or so of these.
And you should familiarize
yourself
with what circumstances
semantically those things should
be used in.
And then when you want
a font in your app,
you should be using
one of these.
Okay? For user content.
There's also system fonts.
These are what goes on buttons.
Okay? Don't use the system
fonts for user content.
Okay? Sometimes it's okay to use
a preferred font on a button.
It depends on whether the title
of the button might change,
depending on user's,
you know, content.
Basically it's the user's
content on a button.
That would be okay.
But you generally wouldn't want
to use system fonts
for user's content.
Okay? So this is what's
on a button, what's --
you know, that kind of thing.
All right.
UI font descriptor.
I put some extra slides in
what I posted that talks more
about UI font descriptor.
I'm not going to go
through them here.
You can look through them,
just kind of get a little bit
of a hint for UI
font descriptor.
But the bottom line is:
Fonts are designed not
by computer programmers
but by artists.
Okay? Artists design fonts,
and they've been designing them
for hundreds of years.
Yeah, probably couple hundred
years since the ledgers,
since presses were made.
I don't know when
Gutenberg was exactly.
Testing my history here.
But those were designed.
You know, back then
you actually etched
on pieces of lead or whatever.
Now they're designed
in, you know, PhotoShop
or Illustrator probably
type, you know,
vector graphics designing tools.
And the problem with that is
that they don't fit what we
computer scientists want,
which is we want the bold
version of this font,
we want the italic version,
we want the narrow version.
Okay. Unless the font designer
actually designs a bold font
or an italic font
[inaudible], we don't get it.
Okay? We don't get one of those.
We could try and somehow
scrunch it up to look more bold,
but that usually
looks, like, bad.
Okay? That does not look good.
So UI font descriptor's
new in iOS 7.
It attempts to put categories on
fonts that defy categorization.
Okay. So the UI font descriptor
has a lot of knowledge in it
about faces and is there
a bold version of this,
is there a condensed version,
is there an italic version?
And so it maps that
into something we,
as computer scientists,
want to do because we want
to put something in
bold on the screen.
Okay? So that's what UI font
descriptor is all about.
Even size, by the way,
is designed into a
font often, okay?
A designer of a font
will design a larger S
with a little more
curve here and there
than a smaller S. Okay?
Size is not just a matter
of vector graphic zooming in
and out -- sometimes,
it depends on the font.
So anyway, look at that,
at slides that are in there
to try and figure that out.
There's nothing you will
have to do in your homeworks
that is font descriptor.
You might have to do fonts
but not font descriptors,
I don't think.
Okay? You might want to if you
want to do some advanced stuff.
So understand, though,
that, yeah,
when you do a font
descriptor and you ask it
for a bold version of a font,
you might not get
a bold version.
You'll get the best thing
it can come up with,
but it might not
actually look bold,
depending on what font it is
and whether it has
a bold, etc. Okay.
So now let's talk about
how text looks on screen.
Well, the font is a big part
of how text looks on screen.
Depending on which font
you pick, that's going
to determine a lot of
what it looks like.
But there's a lot
of other things
that determine what a
font looks like on screen.
For example, is the
thing underlined?
Is it outlined?
Okay? How strongly stroked is
the outer edge of the font?
Okay? Those things are all kind
of independent of the font.
You can apply these
things to any font.
So there's a new class that
you're going to learn that's
in Foundation called
NSAttributedString.
And an NSAttributedString,
very, very simple.
It's like -- it is
not an NSString --
but it's like an NSString
where every character has
a dictionary of attributes.
And those attributes
are like underlined,
or stroke width,
font, etc. Okay?
Now, the reason I say
it's like NSString --
it's not a subclass of NSString.
You cannot send it
string messages, okay?
So that seems like a
significant restriction.
And it is, and we'll talk
about how we're going to deal
with that in a second.
You set the attributes
simply by calling --
sorry, this is
NSAttributedString.
It's immutable --
immutable -- not modifiable.
So you cannot set the attributes
of an NSAttributedString.
There is a mutable
attributed string;
we'll talk about
that in a second.
So you get the attributes by
calling attributes at index.
And it will return
you a dictionary
with all the attributes for
the character at that index.
And that NSRangePointer,
if you pass it a pointer
to a range struct, it
will fill it in with
"How many characters have
the exact same attributes?"
Okay? So it's basically
you specify the location
that you want the attributes
and if a whole bunch
of characters have those exact
same attributes, it will return
that range if you ask it.
Does that make sense,
what that range is?
It's basically just telling you
how many characters have the
attributes you asked
for at that character.
You can pass null if you
don't care and just want
to know the attributes
of that character.
So NSAttributedString
is not a string.
But we want to do
string-like things.
We want to search for other
substrings and things like that,
that we do on a string.
So there's a method in
NSAttributedString --
really important one
-- called "string."
Okay? And this will
return an NSString
that you can then search in
or do all the string
things you want.
For example, if we wanted
to search, there's a method
in NSString called
"range of string,"
which returns an
NSRange that tells you
where a substring
is in a string.
And so we can just say we have
an attributed string lying
around and we're looking
for some substring;
we just say attributed string
string, range of string string,
and we'll get the range back.
Okay? Now, that string
method is guaranteed
to be very high performance
because you're doing
this all the time.
You want to look
at the NSAttributedString
like a string.
So it's high performance.
However, it's also volatile.
The bottom line is this thing is
probably returning you a pointer
to that NSAttributedStrings'
internal data structure,
or some parts of
it, or something.
You don't really
know what it is.
You know whatever it
returns is an NSString.
But so if you want to keep
that thing around for more
than just right there where
you call it, make a copy of it.
Okay? Then you have a
copy of the NSString.
You can hold onto it.
You almost never need to do
that because you're
almost always operating
on the string right
there in place
like this -- a range of string.
You're just trying to get it.
Okay? Okay.
So that's string.
Very important property
in NSString.
So there is a mutable one.
Okay? And mutable
one, it does inherit
from the nonmutable
attributed string.
But it's not an NSString
or an NSMutableString.
It's an NSAttributedString.
And it adds these methods to add
attributes and set attributes
at various ranges inside
the attributed string.
Okay? Exactly what
you would think.
And we're going to
talk about what's
in these dictionaries
in a couple slides.
Now, what if you want
to modify the characters
in a mutable attributed string?
Okay? Exact same thing
as the attributed string.
When you want to look
at the characters,
you call this method
mutable string.
And it will return
an NSMutableString.
And believe it or not, if you
modify that mutable string
that you get back, the
mutable attributed string,
its attributes will
track your changes.
So like, if you insert
some text,
the new text will
get the attributes
of the character right
where you inserted it.
Okay? If you delete characters
out of that mutable string,
then the mutable
attributed string,
those character attributes
will just go away.
Make sense?
So these classes --
NSMutableString and
NSMutableAttributedString --
are in bed with each other,
just like NSAttributedString
and NSString are in
bed with each other.
Okay? I don't know how
they did it at Apple,
but it's really nice because
it makes it really easy
to manipulate both the
characters and the attributes
in an attributed string.
Okay? Okay.
So what kind of attributes are
in those attributes
dictionaries?
One of the big ones is the font.
Okay? So this is a dictionary.
The key for the font
is NSFontAttributeName.
Okay? And you can look up these
keys by going and looking --
if you look up
NSAttributedString
in the documentation,
there's a link there,
which is UIkit additions
to NSAttributedString,
and all the keys that I'm
going to talk about are there.
And one of the keys is
NSFontAttributeName.
And the value of
that is a UIFont.
So this is where you
would get a preferred font
of a certain style,
like a headline,
let's say, in this case.
Okay? So if I had a dictionary
that just had this in there --
nothing else -- the
default text color is black.
Probably my letter A
would like look that.
Okay? What if I added this key
value pair to my dictionary?
NS Foreground Color Attribute
Name, UIColor, blue color.
So here the key is this
foreground color attribute name;
the value is a UIColor.
So that changed it to blue.
Okay. And I could change
it to green if I wanted to.
Be a little bit careful when
you create an attributed string
that has colored text
because in iOS 7 the color
of text sometimes
is an indicator
to the end user what
they can touch.
Okay? And so if -- turns
out apps in iOS kind
of have a color theme.
The default is blue.
That's why on Machismo buttons
that we make will be blue.
But they can be different
colors like orange.
It depends on what tint
you want your thing to be.
But whatever your
color is of your app,
that color you can
usually tap on.
Okay. That's the color of text
on buttons, text at the top
of the screen to
navigate places.
So be careful not to
set anything else to be
that color unless
you can tap on it.
Okay? Be real careful
with color.
There's also stroke with
attribute and stroke color.
The with attribute --
and pay attention to this
because you'll need
this probably
for your homework
-- it's an NSNumber.
If it's a negative NSNumber,
then that means fill glyph,
you know, the A fill it,
and stroke around the edge.
If it's a positive number,
it means just do the stroke
around the edge and the
middle is transparent.
Okay? What else can we have?
Underline style attribute name.
So that's an NSNumber
that has an e num,
one of NS style underline
style single or double.
Or there's also NS
underline style none.
That would be no underlining.
There's also background color.
So here just to show you this is
possible, I set the background
of this glyph to be
a transparent yellow.
Okay? It's thirty
percent visible,
thirty percent towards
opaque yellow.
So you see how you can see the
chalkboard shown through there?
I don't know if that
will show [inaudible].
But here hopefully
you can see --
I can see through that
yellow background.
Okay? In your homework,
you might want to think
about using transparent
colors somewhere else.
Okay. Not the background
of a character
or maybe the fill
color or something.
Anyway, okay.
So transparent colors good.
Okay. So hopefully you're
all getting a feel, then,
for how we build
this dictionary.
Okay. All we need to do is set
the attributes of the characters
that we want to have this
particular set of attributes.
Okay? So where do we
use attributed strings?
So I can create an
attributed string.
It's got all these attributes.
Okay. Where do I use it?
Well, I can use it in a button.
Okay. I can set the
title of a button
to be an attributed string.
That might be useful
for your homework.
We can create a UI label that
has an attributed string.
And a very important class,
which I'm probably going to talk
about next time,
which is UITextView.
UITextView is like a UILabel,
but it's editable, selectable,
scrollable, etc. Okay?
So let's talk about button.
Actually, I'm not going
to talk about button,
except for to say it's
important for your homework.
It just has a method --
set attributed title --
just like it has set
title for a state,
it has set attributed
title for state.
And you're going to
want to use that.
It's also possible to draw
strings directly on screen.
But we haven't talked about
drawing on screen directly yet.
So we'll postpone until we
talk about that next week.
But we will be able to
draw attributed strings
on screens directly, just like
we can draw lines and things
like that directly on screen.
UILabel has a property, it's
an NSAttributedString called
"attributed text."
It's just like the text
label, which is an NSString,
which we've already
used in this class,
we like the score label
and the flips label.
We set the text property.
So there's an attributed
text property.
And you just set the property
via an NSAttributedString
instead of an NSString.
And that's it.
Unfortunately, it's read-only.
Okay. It's immutable.
That property you see is not an
NS Immutable Attributed String;
it's an NSAttributedString.
So if you want to change
the attributed text that's
on a UILabel, you have to get
the label, make a mutable copy
of it, modify it however
you want, and put it back.
Okay. That's if you have an
existing label and you want
to make it be blue instead of
green or something like that.
You have to get it,
create a mutable copy,
modify the attributes,
put it back.
Okay? You don't need to do
this very often on labels.
Labels don't really
have attributed text
on them that much.
Maybe to set the color.
Possibly if they're
specialty labels that are kind
of specifying something
that's not just normal text.
So it's not that
common to do UILabel.
So that's all I'm going to
cover for today, I think.
We do have a Friday section.
The time is being confirmed
to me probably as
I speak right now.
I will post that
for you on Piazza.
It's on Friday.
I believe it's going to be at
1:00 o'clock on Friday in 102.
Okay, unit 102.
But don't hold me to that yet.
Look at Piazza.
We're going to be
talking about debugging.
There are some new
debugging things
for iOS 7 that are pretty cool.
We'll get to a couple of them.
And we're also going to talk
about Xcode tips and tricks.
So command key combinations that
are really valuable to have,
how to set some preferences
up to make your experience
a little nicer.
So it's totally optional.
You don't need to go there.
A lot of you know Xcode.
You're probably used
to debugging,
at least in other languages.
So, you know, if you
miss it, it's not going
to be the end the world.
But it might be valuable.
Next Monday I'm going
to talk about UITextView
since it's the most
important user
of NS Mutable Attributed String.
Okay? And then I'm
also going to talk
about the radio station
from MVC.
Remember that MVC model?
I told you that sometimes
communication happens
by radio station,
where you broadcast
and some other objects tune in.
We're going to talk
about doing that.
And then I have a big demo
that does attributed strings,
and text views, and
all that stuff.
And then we're going
to go start talking
about the view controller
lifecycle, okay,
which is your view controller.
It comes into existence.
Things happen to it.
It appears on screen
and goes off screen,
changes size, things like that.
And then it goes away.
Okay. It goes off screen
and maybe even disappears.
And as all that happens, you
get notified by the system.
Okay? And it's important
to know when you're going
to get notified and what to do
where in terms of
that notification.
So we'll be talking
about that on Monday,
view controller lifecycle.
Super important one
for your next homework.
You next homework
might go out on Monday;
might go out on next Wednesday.
I'm not quite sure yet.
But in case, it will
be due a week later.
So that's it.
And if you have any
questions, I'll be here.
And I'll see you next time.
>> For more, please
visit us at Stanford.edu.
