[ Music ]
>> Stanford University.
>> Okay, well welcome
to lecture 16
of Stanford CS193P
fall of 2013-14.
So today we are going to talk
about the last of the segues,
which is modal segues and
their kind of related segue
which is unwinding segues.
Okay these can be a little,
modal segue's really easy.
The unwinding, you know,
can be a little confusing
and so hopefully both the
combination of the slides
and the demo will get you there.
But it's an important
one to understand,
these unwinding segues.
Also, briefly we're going
to talk about text fields
which we haven't covered
yet and also alert
and action [inaudible] and
then I'm going to do this demo.
It says camera time permitting,
but we will definitely
not have time for that.
That's what we'll start
off on Wednesday with.
All right?
All right, modal view
controllers, this is another way
to segue, another way to put
a view controller on screen.
You already know about popovers
and you know about push segues
in a navigation controller.
So this is another way called
modal view controllers.
And a modal view controller is a
way of putting a view controller
on screen where it takes
over the entire screen, okay?
For the lifetime of that view
controller being on screen,
it's in charge of the
entire screen, okay?
On the iPhone it takes
over the entire screen
by covering the entire screen.
On the iPad it usually takes
over by being in a popover.
And as we know, popovers
are essentially modal.
They're in a mode.
When your popover comes up,
everything else is
kind of dark gray.
And if you click
on anything else,
the popover goes away, right?
So it's essentially
taking over as well.
So modal view controllers
are a way to put things
up on screen that takes over.
So let's look at the
iPhone version of this.
Here's a little demo of it.
So this is the contacts app
and you can see I've
got my contacts there,
my winning contacts,
and so what if I want
to add another contact here?
Let's say I want to add
Montay Ball [assumed spelling]
or something like that.
How would I do that?
Well I would press that little
plus up there in the corner,
and what would happen
when I press plus?
So let's watch.
So I hit plus, and a whole
new view controller slides in
and completely takes
over the screen.
Now this was not a push.
Okay, that cancel button there,
that's not a back button, okay?
It actually took over
the whole screen.
Now cancel happens to be in the
same place that back would be,
which is kind of decent
UI consistency there,
but it's a different, totally
different modal mechanism, okay?
So not only, so we have this
modal view controller that's
taking over the screen.
And for example, there's another
button on this one, add photo,
which uses another
modal view controller
and covers this guy's screen.
So let's watch what happens
when we hit add photo.
See? That covers up
the whole screen again.
So now we have two levels of
modal segues happening here.
And again it's not a push,
there's no back button.
In this one the cancel button
happens to be on the right.
And I don't have any photos
or videos to choose here
on this device that
I'm running on,
but you can see no
back button there.
Now, when I cancel, okay
and this modal view controller
goes away, watch what happens.
It disappears.
I go back to the
previous modal obviously.
And then if I cancel this
modal, okay, then I'll go back
to the previous one from that.
So modal takes over the screen
until it's, you hit either done
or cancel or something and
then it goes away and goes back
to where you were,
exactly where you were.
Okay? So, it's pretty
straightforward but just want
to make sure you understand
what we're doing here
with modal view controllers,
okay?
Now some things to think about,
modal segues can be a little
disorienting to the user
because they're in their nice
app, they're really comfy,
and then all the sudden their
whole screen is completely taken
over by something else.
And like whoa, what's this?
Now, you know, if you're
using modal view controllers
in the proper places, it's okay.
The user's fine with that.
Like the contacts, they're
adding a new contact,
they understand okay well I have
to completely specify this
contact before I say done,
so I kind of can't do anything
else anyway until I'm done.
But modal view controllers
can be overused.
I see students overusing
it a lot.
They're just kind of like oh,
well I need to put the view
controller on the screen
so I'll just put it
up modally, okay?
And, whereas it might be better
to push it onto screen if it's,
if going back makes
sense at all times.
Okay? If you push something and
it doesn't make sense to go back
at all times, then push is
probably not right, okay?
But then you might ask
yourself, can I design my UI
so it is always okay
to go back, right?
You know, in a navigation
controller.
So modal view controllers
tend to get overused.
Users can sometimes
by disoriented by them
so use them with care.
How do we set a modal segue up?
Super simple.
Got our story board, have
the view controller you want
to modal segue to,
we just control drag.
Okay? Control drag, and
when it says what kind
of segue do you want
you say modal instead
of push for example.
And bam, that's all that's
necessary to set it up.
And it's a normal segue
so you're going to prepare
for segue just like
any other segues.
It's very, when it
comes to pushing it,
or you know not pushing
it, putting it on screen,
it's very much like pushing.
So it's very, you'll
be very used to that.
It can be manually
segued to just
like we talked about last week.
You can even put them up by
creating view controllers
and put them on screen but we
don't really talk about that
in this class because
that's really old style way
of doing things.
We do things in storyboard
and we control drag
to set up segues.
So it's normal to prepare.
What does a prepare look like?
It looks like any other
prepare for segue, right?
You get the destination
controller,
maybe check the identifier.
You see what class it is.
You know you set
up your des- your,
you prepare by passing
whatever public API
that view controller wants.
Okay now here's where modal
segues get interesting though.
That's hearing back okay?
So a modal segue has gone
off and done something
like created a new contact
in your contact app,
and now the contacts app,
you know the view controller
that put it up wants
to hear back.
Okay well what was that
contact you just created?
Okay so this hearing back
is kind of the interesting
yet another kind of segue.
Okay? This hearing back we
call these unwind segues, okay?
An unwind segue means
you're going back
to someone who put you up.
Someone who put you on screen.
We call a view controller that
puts another view controller
on screen, a presenting
view controller
because it's presenting this
other view controller, okay?
So an unwind segue,
you're going back
to someone who presented to you.
Unwind segues can only go back
to someone who presented you.
You can't unwind to someone
else who didn't present you.
But in the case where
we had modal and then
that modal brought
up another modal,
you can unwind two
levels at once.
Okay so you can unwind
to anybody
who presented you either
directly or indirectly.
Most interesting thing
about unwind segues,
they're the only kind of segue
that doesn't create a new
view controller, okay?
Every other segue--
pushing, mo modal, replace--
all these segues always create
another view controller.
They instantiate one
from scratch, every time.
Okay every time you push
in a navigation controller,
you get a new view controller.
Every time you modally
segue, you get a new one.
Unwinds obviously don't do that
because they're unwinding back
to someone who presented you.
They obviously already exist.
Does that make sense?
See what I'm saying?
So it's kind of a--
unwind is kind
of a weird segue in that way.
It always goes back to
somebody who already exists.
Normally this unwinding
is used with modal.
It actually can be used
with pushing though.
You could push and push and push
and then unwind all the
way back up to the top.
Okay so unwinding can be used
inside navigation controller,
but most often probably
used in modal controller.
Okay so let's talk about
unwinding and how we set that up
and how we make it work
because it's a little, again,
like I say it's a
little disorienting
because it's graphically
not shown in the storyboard
in the same way as
other segues, okay?
There's not the line
being drawn.
But the way you set it up,
and the most important thing
about an unwind segue is
to specify the action method
that's going to get called
in the presenting
view controller--
the one that's presenting
these guys--
some method has to be called
in them when you unwind, okay?
That kind of method,
it's an IB action, right?
It's the kind of
thing that Xcode is,
pays special attention to.
So it looks kind of like
a target action method,
but the argument is very
important to get right.
It's a UI storyboard
segue, okay?
That's because when this unwind
happens, this method's going
to get called and it's going to
pass you the unwind segue, okay?
The segue itself that
is happening is going
to be passed to you.
And when you look in that
segue, you can for example find
out who's the source
of this unwind.
That's going to be the thing
you presented or the thing
that you presented that somebody
else presented or presented
down the way, that's going to
be the source view controller.
So this is the only
case where we've looked
at the segue's source
view controller.
Usually we're looking at
the segue's destination.
But in this case the unwind
segue destination is receiving
this message so it
knows who it is,
and so it's looking
at the source.
Okay so obviously the first
line in a segue method
like this is usually who's unwi-
who am I unwinding from, okay?
Now that you know who you're
unwinding from, you could ask
that thing, like the contact,
the add contact view controller,
what was the contact
you added, okay?
You just unwound to me.
Obviously you've
chose your contact.
What was the contact you added?
And so now you've got the
contact, you could add it
to the list of contacts or
whatever you want to do.
Okay? So creating that method is
the most important thing to do,
and just the very creation
of that method will
automatically make Xcode realize
that you can unwind to
that view controller.
If a view controller has this
kind of method, IB action,
any name takes a UI
Storyboard segue,
that view controller can
now be unwound to, okay?
So any view controller that that
view controller presents can
unwind back to it.
Okay so how do you
set up that unwind?
Okay this is a little odd.
In the, let's say, add
contact view controller,
the one that's being presented
modally, it might have a button
in there like done or save new
contact or create new contact.
That button, okay, really wants
to start this unwind segue.
But you can't control drag from
that button all the way back
to the other view controller
that has this method.
You'd think you could,
but you can't.
Instead, you control
drag from that button
down to the little
green button--
you see that image
I have there--
the little green button at the
bottom of the view controller
that is starting the
unwind segue, okay?
The thing that was
presented modally.
So you go down to
that green thing--
and when you do to that
green thing and you let go,
it's going to give you a
list of all these methods
like done right there.
Okay all the methods
that are IB actions
that take UI storyboard
segues as arguments.
Now some of those
methods might be
in completely unrelated view
controllers off somewhere else
in your storyboard because it's
going to show you all of them.
Xcode knows about all of them.
It shows you all of them.
If you pick one that wasn't,
is not in a view controller
that presented you, the
unwind just will not happen.
It's like you did nothing.
It's not going to crash but it's
just not going to do anything.
So the done button would
just do nothing, okay?
But if it can find, at run
time if it can find that method
up the change of, chain
of who presented you,
it will call that method, okay?
Now that's only part
of unwinding.
Part of unwinding is
letting the view controller
who presented you know
yeah I'm done, okay?
And here's from public API
and myself [inaudible]
get information out of me.
But there's another part of it
which is preparing
that unwind segue.
So the unwind segue has
to be prepared as well.
And in fact preparing an unwind
segue is even more important
sometimes than preparing
other segues
because it's the only chance
that the presented modal
view controller has
to do anything before
it goes away.
Okay? And that's to prepare
that unwind segue to go back.
So in the demo we're going to do
a photo, some more photo mania
and we're going to add a photo.
We're going to allow us to take
a photo with the camera instead
of getting it from Flickr, and
when that modal view controller
that lets you add that photo is
done, it has to put that photo
in the database before
it unwinds.
So it prepares for the segue
back when it's done by putting
that photo in the database.
Okay so preparing for unwind
segues is very important.
Now, the thing about
preparing for segues is you,
when you do the prepare
for segue,
you need the segue's identifier,
because you've got to know
which unwind segue
am I talking about
and that is also difficult
with unwind segues.
The only place to set that
is in the document outline.
Okay so when you create an
unwind segue by control dragging
down to the little green thing,
in the document outline
there'll be a little line
in there unwind segue, you
know, from a whatever button.
And you can click on that
and then inspect it just
like any other segue and say
the identifier is whatever.
And then in prepare for segue
you'll have the identifier.
Why is that different
or a little hidden?
Well because unwind segues
don't have a, you know,
a drawing on the storyboard
that says where they go
because they don't
really know where they go.
It depends on who presented
them as to where they unwind to.
So there's no line
showing them going back.
So that's why you have to use
the document outline, okay?
So I'm going to demo all this
so hopefully it'll all
make sense once you see it.
How about dismissing modal
view controllers from code?
So you just want to
get it off the screen.
You're not going to
unwind, you just want
to get it off the screen.
By the way, unwinding
automatically takes it off
the screen.
If you have a modal view
controller and you unwind,
it will automatically be
removed from the screen,
you do not have to dismiss it.
But you can also
dismiss them manually
by sending the message dismiss
view controller animated.
This method is sent
to the presenting view
controller, not the presented.
The presenting, okay?
You say to a view controller,
dismiss view controller
animated.
It means dismiss
any view controller
that you have presented, okay?
And luckily though if
you want to kind of say
that in the actual
view controller,
there's a nice method in UI view
controller called presenting
view controller which will
tell you who presented you,
if anyone presented you.
So that's a, you can
dismiss yourself basically
by saying self [inaudible]
presenting view controller
dismiss animated.
And since by definition
that guy presented you,
when you dismiss it's
going to dismiss you, okay?
So just a little frowned upon
because some people would argue
that when a view controller,
modal view controller gets
cancelled, you want to unwind.
Even if you're not
communicating anything back,
just want to let the guy
know, yeah I got cancelled.
If you just cancel yourself
by dismissing yourself,
then the guy who presented
you doesn't get notified
that you submitted yourself.
But some people say yeah but
if I'm cancelling I don't want
that guy to know that
I'm, I didn't do anything,
I didn't add the contact
in the contact case,
so I don't even want
him to know.
So I'm just going
to dismiss myself.
So it's kind of an art
of programming as to
which you believe is
the right thing there.
It's usually not an issue
because in your storyboard
you're wiring it up anyway,
so you could always
wire it up as an unwind
that cancel button instead
of having the cancel
button do target action
and dismiss itself, okay?
You can always just
disconnect any target action
that might be set up.
Okay how does the modal view
controller appear on screen?
That's set by this modal
transition style property
in the presented view controller
and it has various choices here
like cover vertically is
slide up from the bottom
like I showed in the demo there.
There's also flip horizontal
which will flip the new
one in horizontally.
There's also cross
dissolve, right,
which kind of fades
the new one in.
And partial curl which will
curl up the current one
and show the new one underneath.
That one's kind of a
weird one, so you'll want
to check the documentation
if you want to use that curl.
It puts some limitations on you.
Once you curl it, you can't
go modal again for example.
You can't present another one.
Also the one that curls up,
doesn't get view did disappear
because it doesn't disappear.
It kind of just curls up.
You can't really see it
behind the curl but it's still
on screen so that's a little
weird programming wise.
Okay normally a modal
thing comes up
and the one behind it
gets completely covered
so it gets view did disappear
because it's view did disappear.
It was completely
obscured by the modal one,
but with the curl, not so much.
So be careful with curl.
Now what about all this
business on the iPad?
Okay, so on iPad again
mostly we're going to try
and do popovers for this
kind of stuff instead
of modal view controllers.
But you can do modal
view controllers
and you can even have a modal
view controller that controls,
covers the whole screen.
And you determine how
it works, how it covers,
using this modal
presentation style property.
It's a different property,
and one of the options
is full screen--
not recommended on the iPad.
There's page sheet
and form sheet
which are just different
size versions
of the thing on the iPad.
The rest of the iPad screen
will be dark gray, you know kind
of grayed out like a
popover's background is,
and then it'll show up,
one's portrait sized,
one's a little smaller.
And then the current context
is an interesting one.
If you have a popover, if
you have a view controller
and popover and that view
controller does a modal,
then if its current context,
which is the default,
it'll appear inside the popover.
So it'll be modal
inside the popover.
You see what I mean?
So it's going to keep the same
context as the view controller
that presented it, okay?
So anyway you can look
all this up for details.
It's all settable in Xcode as
well, these two properties.
All right so that's it for
modal view controllers.
I'm going to demo it so
you'll see it all in action.
All right, different
topic, UI text field.
So we've seen UI text
view and UI label.
Okay these are kind of two
ends of the spectrum of text.
UI label, non editable.
You know you can have
attributed text in there
but it's static text, can't
select it or anything like that.
Usually one line of text.
Then you've got UI text
view which is almost
like a text editor, okay
fully editable, all fonts
and colors, everything we want.
So UI text field is kind
of in between those two.
Okay? It's a UI control, like a
UI button or something like that
that you can set up
target action from.
And that target action
can happen
when you're done editing
the text or other things
that are happening in the
text and you can just,
when you control drag to do it
you'll see the options you have
in the little target
action window that comes up.
But it's also usually
just one line of text.
It's not like UI text
view that has [inaudible].
Also, the user is usually
just providing the text,
they're not doing
any colors or any
of that attributed
text business.
Generally UI text
field is just the text
and nothing but the text, okay?
Having said that, it's
got a lot of features
to make it really cool for doing
things like entering passwords
or having a search field,
all those kind of things.
So it's a pretty
powerful little class.
But it's kind of like an
editable UI label if you want
to think of it that way.
One thing that's interesting
about a UI text field
of course is that when you click
in it, the keyboard appears.
Now we didn't really talk
about how this keyboard appears
when we talked about UI text
view, but how does that work
that the keyboard appears?
And the answer is, there is
a method called become first
responder that is sent, that
if you send it to a text field
or it gets sent to a text field,
will cause the keyboard
to appear.
So this is a method you
send to the text field.
You can also send
it to a text view.
And when you do that,
the keyboard will appear.
And similarly, if you want
the keyboard to go away,
you send a message to the text
field, resign first responder.
But first responder means
where do keyboard presses
on the keyboard go?
Okay? So if you say
become first responder,
the text field becomes
the first responder
and the keyboard will appear
and key presses will go
to that text field and similar
to resign, it'll go away.
Okay?
There's a delegate for UI
text field unlike UI label
and there's a lot of
stuff you can see there.
I'll show you a brief
example in the demo.
For example, when the keyboard
presses the return key,
okay when the return
key is pressed
and that text field is being
edited the text field's delegate
will extend this message,
text field should return.
Return yes or no whether
it should send its target
action basically.
And in there you can do things
like resign first responder.
So when the keyboard comes
up, someone hits return,
you can make the
keyboard go away
which is usually
what users expect.
So we'll see that
in the demo as well.
But there are other
delegate methods,
I just want to give you an
example of one of them there.
There's probably
about 10 of them.
Check out the documentation
on that.
Over here's another one,
text field did end editing.
That's sent to the delegate
when it resigns first
responder, okay?
So when it stops
being first responder,
this message gets sent.
It also has a radio
station that it broadcasts
on every single keystroke.
Okay so if you want to find
out every single
character that's typed
in your text field you
can sign up to listen
to this radio station and
you'll find out what's going on.
And like I said, UI text field
is controlled so you can set
up target action as well.
So there's a lot of ways
to find out what's going
on a text field depending on
the granularity that you want.
The keyboard, the
exper- we don't,
there's really no property
like give me the keyboard
so that I can set
properties on it.
Okay when you want to control
the appearance of the keyboard,
you have to send messages
to the class, UI text field
of UI text view that brings
the keyboard up, okay?
And those objects, those classes
will all implement this protocol
called UI text input traits.
So these are the set of
properties that you can set
on a text field or
on a text view
that aren't really controlling
anything about the text view
or the text field, they're
controlling the properties
of the keyboard that they
would bring up, all right?
So what are some of the
properties you can have
like auto capitalization.
Sometimes it's nice
you have a text field,
the first character you type,
you want it to be capitalized.
Or every word you type,
separate word you want it
to be capitalized so
you can set the kind
of capitalization
type that you have.
Maybe it's a password.
This text field's a
password and so you want it
to be the dots when
you type them.
Okay so secure text entry will
make [inaudible] the dots.
The return key, when
the keyboard comes
up it has a little return, okay,
and that can have a word on it
like search or go,
okay, or return.
And you can control that
with a return key type.
So these are all things that
you set, properties you set
in your UI text field but you're
really controlling the keyboard.
One thing about the keyboard,
it comes up on top
of other views, okay?
It covers them.
It comes up from the
bottom, covers them.
All right, that can be a
problem if your text field's
at the bottom because you just
covered the thing you're typing
in, okay?
So A, try to design your
UIs so that doesn't happen.
But B, you can for example,
if your view is scrollable,
maybe scroll that text field up
or even just move the whole view
up so that while
the keyboard's up,
you can still see
your text field
that you're typing into, okay?
And so the way you find
out the keyboard's come up
and how much it's
covering is by tuning
into this radio station
UI keyboard will
or did show or hide
notification.
It's a notification sent
by the window you're in.
Okay, self dot view dot
window for view controller.
And the user info that you get
with this radio station
will tell you the rectangles
of where the keyboard appeared
and it's your responsibility
to move it out of the way, okay?
The only class in the
kit, in the UI kit
that will move the
thing automatically
for you is UI table
view controller.
So if you have a row
in a table view that's
in a UI table view controller
and it's editable text
and you bring the keyboard up,
it'll automatically scroll
the table view so move it.
Okay so that's the only one
that automatically does it.
Otherwise it's your
responsibility to make,
move anything that gets
obscured by the keyboard.
Other text field properties,
you can go look those up.
It has a nice left and
right accessory view kind
of like the annotation call out.
You can even add a little
view to the keyboard
with this input accessory view.
There's a lot of stuff to look
at in text field, I can't,
I don't have time to
cover it all today
but you can look it all up in
UI text field's documentation.
All right the last
thing I'm going to talk
about today before the demo
is action sheet and alert.
So action sheet and alert are
things that pop up on the screen
to alert the user of something
obviously or to give them kind
of a branching decision.
Okay action sheet for
branching decisions alerts
to alert them of something.
They have very, the reason
I talk about them together,
they have very similar APIs,
in other words programming
interfaces.
They're used in different
circumstances though.
An alert is more saying
something happened,
pay attention, or I need a
little piece of information,
please give it to me right
now or I can't proceed, okay?
In a little, it's a little bit
like a modal view controller
except for that it can only,
you know, ask a simple question
and get a simple answer, okay?
So that's what an alert is for.
Don't overuse alerts either.
Just like I say don't overuse
modal view controllers,
don't overuse alerts, okay?
Don't every time you need
a piece of information
from the user just put up an
alert and ask them for it.
You know it's nicer for them
to be able to just click
on something and start typing.
Take a look for example
at the contacts app.
Even that contact app where
it brought up the add contact
in a modal view controller,
when it comes to adding things
like text or the, you
know, URLs or emails,
you just click right there
and you just type them in.
It doesn't go modal again
on you just for that kind
of information, so check
that out to see how
that can be nicely used.
Action sheets are, they slide up
from the bottom on the iPhone,
they usually appear on
a popover on the iPad.
They are for really branching
decisions, so the user wants
to do something next but you,
they need to tell you something
so you can decide
which way to go, okay?
So that's what action
sheets are for.
And again they're modal.
They stop everything until the
person answers the question
of what's an action sheet.
So make sure that's really
the UI you want as opposed
to just having, you
know, buttons in your UI
that push different
view controllers.
That's another way to do
branching decisions as well.
And we'll see action sheets.
I'll be demoing those
on Wednesday, okay?
All right, what's the API for
these two things look like?
Very similar.
I'll start with action
sheets first.
You just alloc init it.
Here's the designated
initialize for action sheet.
You can see that
it takes a title--
the action sheet has a
little title at the top.
It has a delegate, okay?
The delegate mostly will
tell you what was chosen
in the action sheet.
Or in alert view it'll tell
you which button was chosen.
There are some special
buttons, a cancel button,
okay which cancels the action
sheet without making a decision.
Destructive button, that's,
you can have one button
in your action sheet like that
and that will be like in red
or otherwise telling the
user, if you choose this,
something destructive's
going to happen.
This is like delete, or
something like that, okay?
So that's what destructive
button is.
And then you can have as many
other titles as you want.
Those are all the other branches
you can take besides the
destructive one or
cancel, not doing anything.
You can also add
buttons programmatically.
If you don't want
to provide them
in the alloc init you can just
call add button with title
to add in the action sheet.
And then it's time to display
the action sheet and you'd kind
of do this, depends on where,
what context you're in.
On the iPhone, you've almost
always going to do show in view.
A lot of times self dot view,
or if you have a view that's
inside your self dot view,
you could show it from that.
But it doesn't really
matter on the iPhone
because it's always going
to slide up from the bottom.
No matter how you present an
action sheet on an iPhone,
it's always going to
slide up from the bottom.
But on the iPad, since it's
going to appear in a popover,
it makes a lot of
sense to, for example,
use show from bar button item
and it'll put the popover
and the little arrow on
the popover will point
at that bar button item.
Or even show from rect.
So you specify an arbitrary
rectangle in your view
and it'll bring a popover
up and point to that.
So for example, let's imagine
you are, have some text
and someone double clicks
a word and then they want
to define the word or copy the
word or something like that.
I probably wouldn't use
it for copy and paste
but do something with that word.
And then you might
say, show from rect
and give the rectangle
of the word.
You see what I mean?
So this is like, this is
what, you know, iBooks does.
You select a word
and you say define,
it'll make a little popover--
that's not an action sheet
but it'll make a little popover.
So you can do the same
thing with action sheets.
Okay so on the iPad you're
going to use show from rect,
show from bar button item.
On the iPhone it almost doesn't
matter which one you use,
it's going to come
up from the bottom.
Finding out which
button is chosen,
this is the delegate
method you get,
did dismiss with button index.
It's all done by button index.
You can look up which
is the cancel button
and which is the
destructive button,
which are the other buttons.
You can also get the button
title and index and compare it
to the one that was chosen.
Be a little careful there
if you're doing localization
because your action sheet might
have localized words in it
and then you want to
see which one is chosen.
Make sure you're
comparing localized,
the localized words, all right?
Or otherwise just use
indexes if you want to kind
of be more localization
independent.
You can programmatically
dismiss an action sheet.
And why would you
ever want to do this?
Okay you put up an action sheet,
a decision branch [inaudible],
why would you ever want
to dismiss it yourself?
Well, the main reason is, you
get put in the background, okay?
So anytime you have
an action sheet up
and someone clicks the home
button to go to another app,
you should dismiss that
action sheet, okay?
Why would you do that?
Well because when the
user comes back to you,
they'll probably be, that
could be the next day.
They might be kind of confused
why this action sheet is up.
They don't remember why they
forced that branching decision.
So you're better to go back
to the previous step for them
and let them choose that
branching decision again
and make the action
sheet come back up.
So how do you find out you
entered the background?
There's this nice radio station,
UI application did enter
background notification.
You just listen to that, boom,
you'll find out you were
put in the background.
Just dismiss the action sheet,
and you know how to do this
with blocks so it's
really really easy.
One liner when you put up the
action sheet to put a one liner
in there that when it gets
to this radio station,
it just dismisses it.
Okay? There's special
popover considerations.
We have the same problem here
with popover action sheets
that we had when
we did PhotoMania
where we kept pressing
a URL and we got more
and more and more of them.
Okay same thing here.
You have to be careful if your
action sheet's already up,
don't put it up again.
Okay? So alert view.
Alert view can have
multiple buttons
like the one on the left.
It can also have a little
text field in it like the one
on the right which
is kind of fun.
And its API looks
exactly like action sheet.
You can add buttons
programmatically.
Showing it is always
just the one method show
because alerts always come up
in the middle of the screen.
I think I said only table
view controllers will move
out of the way.
Alerts will also
move out of the way.
If you bring up a keyboard
because there's a text field
in your alert, the alert
will move up, okay?
So anyway, show.
On either iPad or
iPhone, you just do show.
Here's how you get a
text field in your alert.
You just say alert dot
alertviewstyle equals one
of these styles that
has text: secure text,
plain text, login and password.
And then you get the text
field so you can get the text
out of them by alert view
text field add index.
Okay, index zero if
there's only one text field.
Index zero and one if there's
login and password for example.
So that's how you
can get text field.
All right, time for the demo
so I'm going to show all
of these things in the demo.
And like I said, what we're
going to do is we're going
to enhance PhotoMania
so that it can,
so the user can take
photos with their camera.
Okay? Now we're not
actually going to get
to the camera part
today, but we're going
to do all the rest of it.
Most importantly we're
going to do that modal segue
and unwind segue to put
this view controller
up that's going to
ask for the photo.
Okay it's going to
be a view controller.
It's only job is to let the user
take a picture with the camera,
give it a title and subtitle,
find out their location.
Okay I'm going to go back
and show you a core
location demo here
because I never showed
you that before.
And then now I can
create a photo
because I've got all the
pieces-- title, subtitle, image,
I'll make a thumbnail,
and then the location.
Now I can make a
photo in the database.
Okay everyone understand
what we're going to do?
Okay, let's dive right in here.
I'm going, let's show coming
up because I'm not going
to go back to the slides.
I'll continue this demo by
doing the actual camera part
and then I'm also going
to talk about core motion
which is accelerometer, gyro,
all that stuff, on Wednesday,
okay with another demo.
Friday's section is sprite kit
which is a new iOS 7 kit
for doing 2.5D games.
Okay games that look 3D
but they're really
made out of 2D images.
And then next week
we have off and then
when we come back we'll have
more miscellaneous topics.
Okay so PhotoMania, where is it?
Okay so just before class I
added one thing to PhotoMania
and I'm going to show
you the code I added.
What I did was I
added a photographer
to my database for the user.
Okay this is the
photographer, the user,
who's using my device, okay?
That's because I'm going to
add photos and he's going to,
her or she, is going
to be the photographer.
So how did I do that?
I added these two methods to
my photographer category here,
user in managed object context.
That gives me a photographer for
the user, unique photographer.
And then is user which just
tells me whether a particular
photographer is the user.
And the implementation of
these, I kind of went cheapo,
there'll probably be much
better ways to do this,
but I just created
a photographer
with the name my photos, and I
put a spacebar at the beginning
so it would sort
at the beginning.
But really the way
to do this would be
to add another attribute
to your photographer
which is, is the user.
And then when you sort, you
would sort by that first,
and then secondarily
by the name.
And that would make it so
that this name wouldn't have
to be unique because
it would be the,
you know, that attribute set.
And then here I'm just checking
to see if the user is self.
So that's all [inaudible]
user is.
Okay? The only other
line of code I added
to this was I always create
this magic user in app delegate
when the database
context becomes available.
Okay? That's it.
Everyone understand
what I did so far?
I've shown you everything.
So let's look what
this looks like.
So here I'm running PhotoMania
and you can see right here
at the beginning I have a
photographer, my photos,
and I can click on it.
I'll show all my photos.
I don't have any yet
because we haven't hooked
up this whole camera business.
But what I'm going to do in
this UI is when I'm looking
at my photos, I'm going to
add a little button up here,
looks like a camera,
and it's going
to modally present
a view controller
that lets me take a picture
and put it in the database.
Okay? Good.
All right so that's
what we're going to do,
we're just going
to add this here.
Now, that camera, we don't
want that camera button here
when we're looking
at night flyer.
Okay we don't want that night
flyer to be able to add one,
so we're only going to do
it when it's my photos.
Okay? All right, so how
are we going to do that?
Let's go look at our view.
We're going to do
this on the iPhone.
Probably not going to get
around to doing it on the iPad
on Wednesday, we'll
just do it iPhone only.
Here is my list of
photographers.
Here is that map view with the
photos by a given photographers.
Here's where I want to have
that little map button.
So I'm just going to go
down here and grab a-- oops.
Grab a bar button item.
Here's one right here.
Put it here.
I could say the word camera or
take photo or something here,
but it actually turns
out there's a nice
built-in one for camera.
Whoo, built in bar button item.
Looks good, okay?
So again I only want to
have this camera appear
when I'm showing
the photographer
who is the user, okay?
So I'm going to put a little
bit of code in my photos
by photographer map view
controller which is the code
for that thing, to only show
that button in that
circumstance.
So first of all I'm going
to create a little--
let's go back here [inaudible]--
I'm going to create a
little outlet to it.
Trying to make it more
spacier as I show these.
Okay so here is this guy
right here and I'm going to go
to the dot m. So here's
my photos by photographer
with map view controller.
That's this.
That's where this is.
So I'm going to control drag
from this little button right
here to make a outlet for it.
I'm going to call it the
add photo bar button item.
Okay? So I've got my add
photo bar button item.
And now I'm just going to
put a little bit of code
that only puts that here if
my current photographer--
here's where I set
my photographer
for this thing-- is the user.
So I'm going to have
a little method here.
I'm going to call
it self update,
add photo, bar button item.
And I'm just going to have a
little-- this update this thing.
We need photographer create
for that because that's
where that thing we just added.
All right so here's what I just
typed in right here really fast
and you can look
at this offline.
There's nothing really
new to teach you here
so I'm not going
to go through it.
But suffice it to say it's
really updating the right bar
button items of this
navigation item right here
to have this or not.
So let's go take a look.
Okay so we go here,
it's got this.
Go back here, doesn't have it.
See? Okay so that's good.
So now we need to make it
so when we press this we do
this modal segue to a new UI.
So let's go do that, back to our
iPhone storyboard to make space.
All right so let's make this
new UI that we want to do that,
so I'm going to create a
new view controller here,
drag this out.
Here's my new view controller.
Okay, and we'll line
it up there nicely.
And what is this view
controller going to have in it?
Well, let's see, I'm going
to drag a whole bunch
of nice stuff out here.
It wants a cancel button,
so let's do a cancel.
Okay? That's if I decide eh,
I don't really want
to add one after all.
It wants a done button.
So if we're going to do a done,
it probably wants a take photo
button, okay, that we'll click
that will cause us to bring
up the camera taking
user interface.
I will put these somewhere
here, put that up there.
Let's put this one
lined up over there.
Put this somewhere.
We need a view, I want to have
an image view, a UI image view
that shows me what I just
took with the camera.
So let's drag that out,
put that here let's say.
Maybe, I don't know, something
like let's make it square.
Oops. There, that's
my square one.
Put take photo down here.
Okay, and then I'm going
to have some text fields
for the title and subtitle.
So let's drag those out.
So here's text field,
first time we've used that.
But here we go.
There's one there.
Let's make it a little
wider, [inaudible] like that.
Let's copy and paste
for title and subtitle.
Let's get a label for
each of these things.
There's the subtitle
label and let's copy
and paste [inaudible]
new title label.
And then let's line
these things up.
Something like that.
We'll line up the
baselines probably of our--
let's get that out of the way--
line up the baselines here.
Center's probably just as good.
So anyway, so there's our
title, there's our subtitle.
And now let's create a custom
UI view controller subclass
so we can wire all this
business up to something.
So we can go here, new, file.
And we're creating a new one.
This is going to be a
normal UI view controller.
It's going to call, let's call
it add photo view controller
because that's what
it does, right?
It adds a photo to the database
so that's a good name for it.
We'll put it where all the
rest of our controllers are.
There it is.
Okay, this is our
new, we don't need any
of this boilerplate
that it puts in here.
Get rid of that.
Let's go ahead and set
our identity of this thing
to be this new add
photo view controller.
Let's wire up some outlets to
point to some of these things.
[ Pause ]
All right so, we need
an outlet to both
of these text fields,
so let's do that.
This is our title text field
and we'll wire this one up.
This is our subtitle text field.
And let's light the
cancel button.
Let's wire that up.
Cancel. Done.
Let's wire up the take photo.
Take photo.
Done. Okay.
Now you know I don't like those
like that so we'll do that.
Let's also wire up this
image view right here.
Okay I'm also going to
do something that I did
in image view controller
which I always like to do
when I have an image view
like that, which is I'm going
to have a non atomic
strong UI image star image.
Okay so I'm going to have
a property called image
but I'm going to store
it in the image view.
Same exact thing we did
for view controller.
So here I'm just
going to have-- oops.
Set image.
Okay and it's just going to set
in the image view controller
and return the image
view controller.
And the reason I'm doing this
is because I'm going to need
to do some things when the
image is set in the future.
So I'm just kind of
getting it ahead of myself
and getting it ready for that.
Everyone understand what
I'm doing there though?
Okay. Okay, so let's go ahead
and put this on screen briefly
by creating a modal
segue from here to here.
And I just want to
show you a little bit
about these text fields.
So I'm just going to have this
guy right here go like this,
and instead of push I'm
going to do modal, okay?
So that's going to put this
thing on screen modally.
This is a modal segue
right here.
This for example, we could call
it the add photo segue, okay?
I'll probably skip even
checking that identifier.
But anyway, let's go ahead and
run so we can get this thing
on screen and I can show you
something about the text field.
So here we go, here's
our camera.
And when I click this, it
comes up on screen modally.
Now one thing about modal,
you better have a way
to get rid of it, okay?
And we haven't wired
any of this up.
This is, my app is done now.
I can't get back, okay?
So I have to either unwind or
I have to cancel myself, okay?
But we're not doing
that right now,
what I'm doing now is I want
to look at these text fields.
So if I click here title, okay,
and I could type, start typing
in a title here, and
I'm like okay that's
where I want the title to be.
Oh, I can't get, I can't
get rid of this, okay?
There's no way to get
rid of this keyboard.
Okay there's nowhere
I can click,
there's nothing I can
do, this thing is up.
And my photo is underneath
it, so I can't see my photo.
Okay this is awful.
So I really want to be able
to dismiss this keyboard
when I hit return here.
So we can do that using the
UI text field's delegate.
So let's go ahead and do that.
Okay we're going to
go here and I'm going
to do something a little
interesting we haven't done
before which I'm going to wire
up a delegate in the storyboard.
Normally we would
do this in code.
Like when the setter for that
text field was called we'd say
self, you know, we'd say text
field dot delegate equals self.
But here I'm going to do
it by control dragging
from the text field down
to my view controller.
And when I do you'll see that
I can set its delegate, okay?
So I'm setting the
text field's delegate
to be my view controller.
I'll set the other one too.
So both of these guys, if you
right click on them you'll see
that their delegate is my
add photo view controller.
Now I still have to, in my add
photo view controller right
here, I still have
to say oh yes,
I'm a UI text field
delegate, okay?
All right now again, all
these methods are optional
so it really wouldn't be
that big a deal if I didn't
but still, just to be
proper, I should do that.
And I, now I can implement
some of these ones.
Like a good one here would
be shou- what's it called?
Text field should return.
So here's some of
the text field ones.
These ones [inaudible].
So let's do text field
should return, okay?
And so if the text field
asks me, should I return?
I'm going to say yes,
you should return.
Meaning if you have
target action that fires
when you return,
go ahead and do it.
But I'm also going to
say, Mr. Text Field,
please resign first responder.
In other words, stop
using the keyboard, okay?
So just by putting this
in here, now when we run
and bring this baby back
up and we click here
and we start typing and we
hit return, it leaves the text
in there, even does its little
fixing the misspellings.
And the keyboard goes away.
Okay? And I can bring this one
back and make this one go away.
So it's a much nicer
UI to be able to make
that keyboard go away especially
if you have something
underneath the keyboard
and you don't scroll it up.
Okay? So I just wanted
to show you that just
to show you how we can
A, set the text delegate
in the storyboard, and B, how
we could use a delegate method
to do something valuable.
Okay? So that's all I'm going
to show you for text field.
I think you can figure
out the rest on your own.
All right so now let's get
back to the segueing okay?
So we have this guy right
here and it segues to here.
So we already set
up this modal segue,
but we don't actually prepare
it nor can we unwind from it.
So we really haven't finished
with the whole relationship
between these two
view controllers.
So let's first look
at the public API
of this modal view
controller to kind
of understand how it's
going to communicate.
So I'm going to look
at the public API
of add photo view controller
and it really has two things.
It has an input which
is the photographer
who is taking the photo.
Okay? Now hopefully we always
pass in the user, right,
that special photographer.
But this add photo view
controller can be more generic
about it and just say, hey
give me a photographer,
I'll take a photo and
add it to the database
for that photographer.
But we're going to have our map,
photos by photographer
map view controller.
If it's the user and that
camera button gets pressed,
we're going to pass
in the user's one.
So that's the in, okay?
So that's import photographer.
And we're also going to
import photo while I'm here
because this thing, this view
controller also has an output
which is-- [inaudible],
the photo that was
added to the database.
Oops, photo.
Okay so this is an add
photo view controller.
It adds a photo for
that given photographer
and when it's done doing
that, this will be set
to the photo it added.
So anyone who segues to it, when
they unwind back, they can look
and see what was the
photo that was added?
That make sense what
we're doing there?
So we have to implement
this API both on the way
in and on the way out.
So let's talk about
on the way in first
because that's normal
segueing that you're used to.
We're just going to do this
in our photos by photographer
for map view controller
and all we're going
to do is prepare
that segue, okay?
Before we do that let's go ahead
and import our add
photo view controller
because we're going to use it.
We're going to prepare it.
And so let's do that.
And here's prepare for segue.
This is a normal segue
just like any other segue
and I'm just going
to prepare it.
Let's say if the sender--
no if the segue's destination
view controller is kind
of class, add photo
view controller,
then add photo view controller--
add photo view controller--
equals add ph- yeah you guys
should not be using my bad style
here but that's demo
naming right there.
Segue that destination
view controller.
Okay so now I have the view
controller I'm segueing to here
in this modal segue so I'm going
to set its photographer
that's taking the photo equal
to self dot photographer.
Now this is always going to be
the user because the only time
that little camera
button is there is
when it's the user, okay?
But to be double safe here,
maybe I would want to check
and see is user, right,
[inaudible] photographer
is user.
But I'm not going to be double
safe because it's demo, okay?
So there, that's that segue.
I'm still going to do this segue
if the sender is in annotation.
In other words, someone
clicks on the pin,
[inaudible] do that one too.
I could probably put an
else in here if I wanted to.
Even else if.
Something like that.
Okay because obviously it's
going to be one or the other.
I also probably could've checked
my segues identifier here
to make sure it's add photo.
I can do that if I want to.
But anyway, hopefully this side
of this segue you
totally understand, right?
Okay, normal segueing,
we're just doing it
modally rather than not.
Okay, so now we've got to it.
Now the hard part,
unwinding, okay?
So now we want to hear about it
when the thing is done, okay?
And I told you that that's done
by implementing a special
IB action, okay, method,
and we can call it
anything we want.
And what is going to
happen when it's unwinding?
Well a photo's going
to be added.
So maybe I'll call this
method added photo, okay?
Because that's what it does.
And the real key is that
the argument is a UI
storyboard segue.
Oops, segue.
Okay? So this method is
the method that's going
to get called when
we unwind, all right?
Now the very adding of this has
caused Xcode to know about it,
so that if we go back to
our storyboard and wind u-
you know control drag
to hook up and unwind,
it's going to know about it.
So let's go do that.
We're back in our thing here.
Now, cancel.
Let's talk about cancel briefly.
I'm going to make the
executive decision that cancel,
it's just going to dismiss,
it's not going to unwind.
All right?
And I already have a
cancel method right here.
I already wired it
up for target action.
So how do I do that?
Self dot presenting view
controller presenting dismiss,
yes.
And this completion handler is
called once the view controller
is fully dismissed.
In other words, after its
view did disappear is called.
We don't need to do
anything at that time.
Some people think this, this
is more magic than it is.
It's really just a simple way
to, after this thing is gone,
do something to clean
up or something.
But we're no, we
don't need to do that.
So anyways, so that's it.
So that cancel.
So in fact if we run right
now and we bring our photos
and we go up here,
cancel will work you see?
It just dismisses it.
And it doesn't unwind, it
doesn't call that added photo.
It just cancels it, gone, okay?
Now done, this is the
one we want to unwind.
We want it to create this
photo and then unwind back
to this map view controller
right here and call added photo.
Okay what's, what
are we going to do
when added photo is called?
Well, let's see.
Let's do a couple of things.
One, let's make sure
that the source
of this is an add photo view
controller, which it should be
because it's the only thing
we know how to unwind for.
And also because who else
would call added photo?
But we'll check it anyway.
And then we're going to do, I'm
going to copy and paste this
so I don't have to
type all that again.
Okay now I'm just
going to change,
but this is the source
view controller instead
of the destination
view controller, okay?
So I've got my APVC.
Now I'm going to say, okay
well what was the photo
that was added?
Well it's the APVCs added photo.
That's part of its public API,
the out of its public API.
So I'm grabbing that out,
and now I'm going to say
if we added a photo, then
what might I want to do?
I'm the map view-- I'm showing
photos by a photographer
so I probably want to do,
for example, map view,
add annotation this added photo.
In other words, add
this photo to my map.
I might also want to say
self dot map view show
that annotation, okay?
Zoom in to that part of the
world where the photo was taken.
I might want to say, I
probably want to say photos
by photography equals nil
and have that recalculate
because I've added a new
photo for this photographer.
So the next time someone asks
me about that it'll work.
Otherwise, for instructional
purposes here, I'm going to log
and say add photo view
controller, did not--
or I'll even say-- unexpectedly
did not add a photo.
Okay because if I'm
getting unwound to,
it should have added a photo.
Okay so if this is nil,
then something's wrong.
Okay? So but we're going to see
that happen because we're going
to try this without adding the,
without the photo being added
to the database and
see what happens here.
So everyone understands
what happen-
what's going on here right?
We're unwinding back
to this guy.
This guy is receiving the
unwind and doing something
with the photo that was
added with the add photo.
All right so now let's go
ahead and wire that up.
So as I said, we're
going to pick whatever UI
in here is going to
cause the unwind,
which is the done button.
I'm going to control drag
to this green button.
And when I let go,
watch what happens.
You see how added
photo is in the list?
And every single IB action
that had a UI storyboard segue
as an argument would
be listed here.
Okay? But added photo, obviously
only one, it's the one we want,
so I'm going to click that.
So now I've created an unwind
that will unwind
back to this guy.
And I told you that the only
place you can really see this is
in the document outline.
You can see it right here.
See? Unwind segue from
done to exit, okay?
And I can, this is
a normal segue
so I could set its identifier
for example to something
like do add photo or
something like that
because that's what
this unwind segue does.
It does the add photo.
It's the done basically.
Okay but I wouldn't
even need to do that.
So let's go-- well I will
need to do it eventually--
but for this so far I didn't.
So let's go ahead and see what
happens here when we run this.
Okay so I'm going to go
here, I'm going to go here,
and I'm going to hit done this
time and we'll watch it unwind.
Okay it unwound, right?
It dis- dismissed it, okay?
And look down in my
console down here.
Add photo view unexpectedly
did not add a photo
which is exactly what
we'd expect, right?
It unwound over to
here, did this,
but it never added the photo
because I never take all the
information here that's in my UI
like the title, the
subtitle, the photo--
I never put them into a photo
and added it to the database.
So it's right.
This thing is properly
reporting here
that it did not add a photo.
So let's do that.
How do we do that?
This is where prepare
for segue is
so important for unwinds, okay?
Because prepare for segue--
since this unwind segue happens
in this view controller,
okay-- unwinds over to there,
this guy gets to prepare.
And what this guy wants to do
when he prepares is
create that photo.
Make sense?
So all we got to do to make
that photo is implement prepare
for segue here in this
add view controller.
So let's do that.
Add view controller.
Let's put this right here.
This is normal prepare
for segue here.
We need to figure out which
segue it is and so we could--
we really can't look
at the destination view
controller here, okay?
Because add photo view
controller is kind of like part
of the view of that
other view controller.
So it really can't be
looking, it can't know anything
about the photos by
controller map view controller.
But what we can do is look
at the segue's identifier.
So if the segue's
identifier is what I set there
which was do add photo, right?
That's what I set it
to in the storyboard--
and probably we want to have
this be called something
like unwind segue identifier
or something like that.
We'll put this up here.
Copy, pound sign, define.
Like that.
Okay? So I have a
nice constant there.
We're going to need
this constant
in a second as you'll see.
So if this is the unwind, then
we want to create that photo.
So what do we need
to create the photo?
Well, first thing I need is
a managed object context.
Okay I can't create a photo
unless I have a handle
on the database.
But I do because self dot
photographer taking the photo
has a managed object context,
so I'm going to put this photo
in the same database
that the photographer's
in which is exactly what I want.
All right?
So that's good.
So if that context is not nil,
then we can create our photo.
So photo star photo equals,
and let's import photo.
Okay, so how do we
create a photo?
NS entity description, insert
new object for identity, photo,
and the context is that context.
All right I've created a photo!
Now I just need to set
everything in the photo.
So photo dot title equals self
dot title text field dot text.
Oops. Get rid of
these square brackets.
All right, and photo dot
subtitle equals self dot
subtitle title field dot text.
So here's how we are
grabbing the text
out of those text fields just
using, just like a label, right?
Just grabbing the text
property which is an NS string.
And what else do we got
to get out of this photo?
Well quite a few
other things actually.
We got photo dot who took.
Everyone know what that is?
All right, photographer
taking the photo,
that's who took this thing.
How about photo dot latitude?
Okay, well we don't
have the latitude.
We've got to get that latitude,
so to do that I'm going
to add some properties here.
Okay so I added these
properties.
One is to keep track of our
location, [inaudible] location.
One is to keep track of
the URL of our image.
One is our thumbnail.
And also I'm going
to say add photo,
added photo equals something.
So I'm going to make this
one read right and I'm going
to make this one
read only over here.
So that this is truly an
outgoing parameter, okay?
So I'll make it read
right here internally.
So I need to import
core location,
okay because I'm using
core location right here.
Okay and we're going to
have to set this location
which we'll do in a moment.
But in the meantime,
let's go here.
This is going to be self
dot location dot coordinate
dot latitude.
And photo out longitude equals
self dot location dot coordinate
dot longitude.
And then let's say photo dot
image dot URL equals self dot
image dot URL, absolute
string and we're going to have
to implement this, okay?
Because right now our image
is just in that image view.
We're going to have to put it
on disk and get a URL to it.
So we'll have to implement it.
And then we got photo dot
thumbnail dot URL equals
or do the same thing
here, absolute string.
Okay and then finally
we're going
to say self dot added
photo equals the photo.
Oops. All right?
So in the unwind, in
preparing for the unwind,
we put that photo
in the database.
Now, there could
be a problem here.
What happens if the user
hasn't taken a photo yet?
Okay, they haven't
hit take photo.
Th- I can't do this.
Okay a photo of, blank photo
makes no sense whatsoever.
So this is a normal
segue preparation.
So I can also do bool
should perform segue
with the identifier.
Okay? So this is whether
we should do the unwind
at all when we click it.
So again I'm going to do the
same, if segue identifier is
that unwind [inaudible].
And then I'm just going
to check some things
to make sure things are okay
like if not self dot image,
then I'm going to complain.
So let's say no photo taken.
Oops. Okay or I might
say or else
if self dot title text
field dot text length not--
so if, I'll force a title here
and I'll say self
alert title required.
Too many exclamation
points there.
Otherwise, we'll return yes.
In both of these cases
we want to return no
that we should not segue.
Okay? Now before we go on and
try all this segueing stuff,
let's talk about this okay?
See this little method alert
which I haven't defined yet?
Let's go ahead and
implement that.
This is a good aside for us
to talk about alert view here.
So let's do void alert
NS string, message, okay?
What we want to do
here is put up an alert
that says whatever
that message is.
So how do we do that?
UI alert view, alloc
init this long thing.
What's the title?
Well, we're adding a photo
so we'll say the
title of this alert.
That's the little
title at the top.
Not the message but
the title at the top.
Say add photo.
The message is the message that
we want to give right here.
Delegate, I'm going to make
this one have no delegate.
Show it with a delegate
in a minute.
Cancel button.
There's no cancel, okay?
And the only button is okay.
Okay? So I've created this alert
view, now I'm going to show it.
Okay? Everyone understand that?
So that's just showing.
So let's go ahead and
take a look at this.
What have we got here?
Oh sorry, this is
just the identifier.
Okay. Yeah.
Yeah what else have we got here?
Okay this else return
super should okay?
That's if we don't, if
it's not our identifier,
it's some other one,
then we'll do super.
So let's do that.
All right so we'll go to photos.
We go here.
Now let's try to unwind.
No photo taken.
So did our should
perform put up an alert?
No photo taken.
See that? So that's good, okay?
So we're trying to unwind
so we're getting
closer to unwinding.
We still have to get
an image and we have
to make sure we set our title.
So we're getting closer.
I'm going to take
another little aside
to show you doing an
alert with a delegate.
What if I had something
in my application
which was a fatal
error, fatal alert, okay?
So this is some alert that's so
bad I got to cancel right away.
Just do cancel, okay?
How would I implement that?
Well, I would do the same alert
that I'm doing here, okay?
But instead of having
the delegate be nil,
I'm going to have the delegate
be self so that I can find
out when the user clicks okay.
And when they click okay,
I'm going to cancel.
I'm going to dismiss myself.
So to do this, I need to be
a UI alert view delegate.
Oops. Okay.
And then I'm going to
implement the alert view.
I'm going to do the one dis-
you can see there's a few here--
did dismiss with button index.
That's the one I'm going to do.
And I only have this one
button so I didn't even need
to look at the button index.
I know that in this
case I want to cancel.
Okay? Now I didn't set myself
as the delegate for this one,
so I'm not going to
cancel for a normal alert.
Only for a fatal alert
am I going to cancel.
Now what would be fatal?
What kind of things
would be fatal in this?
Well, what if my
device has no camera?
Okay that's fatal.
It's just a waste of
time to have this thing
up if my device has no camera.
Or, since this PhotoMania
is fundamentally locations
of photos, what if I
can't get the location?
Okay the user maybe doesn't
allow me to get the location.
So let's go ahead
and put a method
up here called can add photo.
We've got to import
some stuff here.
So this can add photo method
is going to check some
of these fatal errors like
do I have a camera available?
I'm asking the UI image
picker controller,
is there a camera available?
I'm also making sure
I can get an image
which really you usually
don't have to check this.
Mostly you're checking this
to see if it'll do video.
All cameras can do image,
but just to show you what
it looks like to check it.
And then I'm also going to
check my location manager
to make sure my authorization
status is not restricted.
So that means my authorization
status is either you're
authorized, or denied.
Now why am I only
checking restricted here?
Because this is going
to be a fatal error.
Okay? It's only going
to be fatal
if the user can't control
whether my app can find
its location.
All right, they can't
go to settings
and set it, so it's fatal.
Later I'll check to see
if they've just denied it
and I'm going to suggest to
them they go back to settings
and undeny it and
then it'll work.
So it's not a fatal
error in that case.
So that's the difference why
we're doing restricted here,
okay?
So if any, if all this is
true, then we're good to go.
We can take a photo.
Otherwise, we can't
take a photo.
So now let's, in our view will
appear or view did appear--
super, view did appear--
I'm going to say if self
class can add photo--
actually I'm going to say if
not-- if I can't add a photo,
then I'm going to self fatal
alert sorry this device cannot
add a photo.
Notice I'm not saying
anything in this fatal error
like you are not authorized
to do, get your location
because there's nothing
they can do about it, okay?
If they have no camera or they
can't do it, they can't go
out of camera or, you
know, do something
about their being restricted
from doing the location.
They can't do anything
so I'm not going
to suggest they do anything.
I'm just going to say
sorry, you can't do it.
Okay? I could imagine
maybe saying here,
sorry this device
cannot have a photo
because you have
no camera, okay?
I definitely wouldn't
want to say
because you cannot
get your location.
Or if I do say that, I want
to say contact your system
administrator or something
like that to get yourself there.
It's, you know, but
here I'm just going
to say sorry you can't take
a photo, and it's going
to be fatal so I'm going to
immediately drop out of there.
So let's take a look at that.
All right there's photos, and
I'm going to bring this up.
And sure enough sorry, this
device cannot add a photo.
Why? Because it's
the simulator, okay?
The simulator cannot
add a photo.
So it's properly telling
me I can't add a photo
and if I click okay, cancel.
Okay so fatal error.
Okay so now we're going to
continue, we're going to switch
over and do it on a device where
we actually can do this stuff.
But to do that, the
next thing we want
to do is location manager.
So I never showed you how
to do the location stuff
and so this is a good
example of how to show that.
So I want to set this self
dot location to something.
Because right now it's
going to be nil, right?
Because I just created that
property and I never set it,
and then here I'm looking at it.
So our latitude and longitude
would be zero so we're going
to be somewhere out in
the ocean somewhere west
of Africa or something.
Probably have pirates
after us over there.
So we don't want to do that.
We want to set this
[inaudible] location.
So how are we going to do that?
Well, to do that I need
a location manager, okay?
So let's find a good
place to put all this.
Let's put it down here, okay?
So I need a location manager and
I, for speed here I have this
to show you how to do that.
So I'm just going to
add this property right?
CL location manager,
location manager,
remember this is
the thing we ask
to start giving us
updates on the location.
And then I'm going to
lazily instantiate it.
Here it is here,
lazy instantiation.
If we haven't created one, then
I'm going to alloc init it.
I'm going to set
myself as the delegate.
Obviously warning because
I haven't said that I'm
that kind of delegate yet.
And then I'm going to
set my accuracy to best.
Why am I doing best?
Because I want to know exactly
where this photo was taken?
And I'm modal anyway
so I'm only going to be
on screen for a few moments.
I'm not going to use
up the whole battery just
finding out where I am.
And then here we set
the location manager.
And then here's the delegate
method I'm going to use, okay?
I'm the delegate, so I'm going
to get the delegate method.
It's called location
manager did update locations.
It gives me an array of all
the locations it's found
since the last time it called
this message, this method.
And I'm just going
to grab the last one.
The last one is always
the most current one,
the most up to date,
the most accurate.
That's the one you
always want there, okay?
If you're just trying to
get your current location.
And I'm just going to put that
in self dot location so that
when I pop it in here it'll
be the right location.
Okay? Now, we're not done here
because this location manager,
we have to start it up.
Okay remember, just because
you create a location manager--
let me go ahead and do
this delegate thing first,
make myself be a CL
location manager delegate.
I need to start it up.
And where am I going
to start it up?
I'm going to start it up
in view did appear, okay?
So I'm going to say else-- okay
this is I can't add a photo.
So else, I'm going to say
self dot location manager--
that's going to lazily
instantiate it starts
updating location.
And that's going to start
sending me those deligate
methods of my location,
all right?
It's probably going to send me
one right away that's pretty
inaccurate, like WiFi
based or something,
then it'll probably send
me another one with GPS
if I'm outside or I can, you
know, see the satellites.
So it might send
me more than one.
That's okay.
I want it to keep
sending me more
and more accurate
ones as time goes on.
If you do this, you almost
always, in view will disappear,
want to turn this back off.
Now it's not that
huge a deal here
because this thing
is presented modally.
Oops, stop updating location.
This is presented modally and
so when this thing unwinds,
it's going to get
released from the heap.
And when it gets
released from the heap,
this location manager's going
to get released and it's going
to stop updating, okay?
So it's really not
that big a deal,
but if for some reason
we ever figured out how
to make this thing not be modal,
put it up in a non modal way,
we just want to be
in the good habit
of every time we turn this
thing on, turn it off somewhere.
Even if it's, you know, turns it
off right before it gets thrown
out of the heap.
Still, turn it off, okay?
Using location updates
is expensive.
Fun to run while
this thing is up,
but we want to make
sure we turn it off.
Okay let's go ahead and, let's
see what else can we do here?
Yeah, let's go ahead and
throw these two methods
into image URL and
thumbnail URL.
So all I need to do
here with the image URL
and thumbnail URL is I'm just
going to take the image that's
in my image view, put it on
disk, and return the URL.
Okay? Where am I going
to put it on disk?
I'm just going to put it in
a randomly named file, okay?
I'm just going to pick a
name, I'm going to pick,
the name is going to be
the number of seconds
since some reference
date in 2001
or something like that, okay?
That's pretty unique.
It's not likely, I mean unless
somehow you did two different
devices identically and
this was over iCloud,
you could conceivably
get a conflict there
but we're just going to do that.
Probably better ways
but we're going
to create both the image
URL and the thumbnail URL.
Let's put those down here.
So the image URL, NS URL,
image URL looks like this.
Oops. Okay so this is the
getter for that method,
so I'm going lazily
create that file.
As soon as someone
wants the URL for it,
I'm going to go create
the file, okay?
So if not image URL--
in other words,
I'm going to lazily
instantiate it.
And we have an image, okay
because we can't create the file
if we don't have an image,
but if we do have the
image then we'll do it.
Let's do this, let's say NS URL,
URL equals self unique
document URL.
Okay so this is just
going to be a unique URL
in my documents directory.
I have that one here
for you, you can look
at it at your leisure.
It just does, you know how to
do all these things already
so there's no use
going over them again.
So I got this unique URL.
If that was successful, then
I'm going to get the image data
out of my image view
and I'm going to do
that through this
kind of cool function,
UI image jpeg representation.
Okay? It will take a UI image
and give you back an NS data
with a Jpeg of that thing.
Pretty cool, huh?
Not all images can do this but,
you know, the kind of images
that we load from the
camera can, for example.
So this would be self dot image,
and then this is how much
you want to compress it,
and I'm going to compress it
as little as possible, okay?
Because I want the image to
be as close to what you took
of the camera as possible.
I don't want any compression
artifacts or any of that stuff
because this is the
actual image you took.
So now that I have this,
I'm going to say if I'm able
to write this thing
out, write to URLs.
So write to URL is an NS data
method and I'm going to specify
that URL, and yes I'm
going to do it atomic
which means it's going to
write it to a temporary file,
delete any existing one, move it
over in one atomic transaction
so if the phone crashes in
the middle, you won't get,
you'll still have an old
file if it were still there.
If it successfully does that,
then now this is the image URL.
Remember this is the getter for
image URL so I'm setting that.
And now we can return
our image URL.
Now one thing is, every time
you ask for the image URL,
I'm writing it out to disk.
Well not every time but the
first time you ask for it.
I better be careful here if
someone changes the image,
I'm going to have to
regenerate this URL.
I also want to delete
that pile off of disk.
So here I'm going to say,
if anyone sets the image
to something new, I'm going
to say NS file manager,
default manager, remove
item at URL our image URL.
Notice I'm not calling
self dot image URL here
because that would
create the file.
Okay? So this is a
little bit weird.
I told you never use
underbar in anything
but a setter or a getter.
I'm violating that
but it's, you know,
kind of for performance
reasons here
and we don't care
if there's an error.
If it couldn't delete it,
it couldn't delete it.
And also I'm going to
set my image URL to nil
so that the next
time someone asks,
because I have a new image,
the next time someone
asks, it'll regenerate.
Okay? So I'm going to
do the exact same thing
for the thumbnail, okay?
I created this file here.
I'm going to drag
in a little category
that I created using some of the
code from last Friday's section
and also some of the
little code that I wrote.
So here it is right here.
Oops, [inaudible] like this.
Put it in here.
Oops, let's go here so you
can see what I'm doing.
Going to put this right here.
This code is quite simple.
It just has two methods.
One takes the image and gets
a new image by resizing it.
That's what we want
for a thumbnail.
And this one applies
a filter based
on what we saw at
Friday's section.
So if you miss Friday's section
you won't understand this code,
but if you were there you will.
And this is pretty
straightforward code using draw
and rect and this nice graphics
begin image context with option
so you can look at
that offline as well.
And so now let's go back here,
and now that I have
that, let u- where was I?
Let's find this thing.
It's way down here.
Here it is.
So we've got the thumbnail, so
the thumbnail uses the same URL
as the image but adds
dot thumbnail to it
and then scales it and then
does exactly the same thing.
So now [inaudible] thumbnail,
so we want to do the same
thing here for the thumbnail.
We better remove our
thumbnail file and we want
to self dot thumbnail.
That's not strictly
necessary but we'll do it.
Okay, so now that we have
thumbnail URL and image URL,
this photo creation
up here will be able
to fully create the photo.
Now we don't have the camera,
but I want to end this thing
by showing you this
working so far.
So I'm going to drag an
image, a little flower--
this is the flower we saw
earlier in the quarter--
and I'm going to make this
little flower be our photo,
okay?
So I'm just going to
do that right here
in view did load of this guy.
View did load.
Oops. Super view did
load and I'm going
to say self dot image equals
UI image image named flower
dot jpeg.
This is an opportunity to
show you another cool thing
that we, I just did.
What you see, I dragged the
file right into my top level
of PhotoMania and then I
can access it directly using
something like image named.
So you don't actually have
to put things in that asset,
so you can put them right
in the top level if you want
and access them that way.
All right, so hopefully--
oops, this is not going to work
because we need to
be on a real device.
There we go.
I've this iPad in iPhone
simulation mode here.
[ Pause ]
All right so we'll
go to my photos.
Here's showing all my photos.
I don't have any yet.
We'll press the little camera.
Here's our photo that
we took with our camera.
We'll do that on Wednesday
so for now we got photo.
We could actually hit done here.
Watch what happened
if we hit done.
It says title required.
Remember we had that should
perform so that's good
that it requires that.
So we'll call this flower
and then we'll have a little
subtitle, pretty, okay?
So we're ready to go.
Now we hit done, it
unwinds, it creates it.
It found our location.
If we click on it, we
see it's got a thumbnail.
We can click to see the photo.
Here's our photo, etcetera.
Okay? Got all that?
Okay, so on Wednesday
we will continue
by actually getting
the photo in here.
I'll also show you
an action sheet.
We'll use that filtering
thing to put an action sheet
up that filters our photo.
Okay? If you have
questions I'm here.
>> For more, please
visit us at Stanford.edu.
