[ Silence ]
>> David J. Malan: All right.
We are back.
So T minus one lectures to go.
Tonight we finish our look at iOS and some of the features
that we've hinted at thus far.
And that might empower you to do some pretty cool things
with your third and final project.
In fact, looking ahead to exactly that,
on Wednesday August 7th in lieu of lecture,
we'll have an App Party of sorts where [inaudible] will convene
across the hall where labs usually are held.
We'll bring in some snacks and food and whatnot.
And you'll bring your laptops and or iOS devices
and the goal would be to spend an hour
or so exhibiting each other's work and chatting and sort
of did he briefing how the semester went.
And showing off what your, hopefully, quite proud of.
Whether that's your final project
or either of the prior two.
And leading up to that, next Monday,
will be a couple of guest lectures.
So I and all the TF's will be here.
But we'd thought we'd invite a couple of friends.
One is a fellow named Dan Armadorez,
who used to could teach this class and taught
in android aspect of it.
What we thought was we'd give everybody some exposure
to what android programming is like what's similar,
what's different so that you can scratch that surface to see
if that's a direction that's a direction you'd might
like to go in next.
And also we'll have a friend of ours
from Microsoft Bob Familiar joins us to talk
about windows mobile programming.
Taking a look at how you might do it with C sharp,
which is Microsoft's language for desktop
and mobile programming as well
as how you might also do it using HTML 5's.
So that'll be our final glance for the semester.
And we'll also tie up loose ends with iOS and give you a sense
of where you can go from here
around what you might want to keep in mind.
So that once the training wheels are off,
you can actually create some cool things on your own
if indeed of interest.
So with that said, how would we go
about making something like this?
So we saw our first application last week involving Rob
last week.
And what were the features we implemented
to top Rob's three photos last time?
Yes? Gesture.
So we had a couple of gestures.
We were able to swipe from left to right to move Rob
from one side to the other.
Or right to left in order to pan
through his three Facebook photos.
Thank you for sending him those Facebook friend request
so quickly incidental ly.
And we also had one other feature
that we implemented atop Rob's face.
Which was what?
Alert, okay.
But we've seen alerts before.
How did we trigger that alert last time?
Yes, so touching down or a long press.
Or if you hold for a good second or two,
that is the separate event that's fired
that we call encode.
And we said, "Hey, stop that," or something similar.
So we had two such gestures.
But we really didn't do a couple
of the more familiar mechanisms whereby I might, for instance,
want to just move something around.
Now this is a little underwhelming on a back drop.
But because this is rectangular, you can imagine having images
or shapes of some sort where it makes sense
to actually move these things around.
And in fact, where it will end tonight is actually looking
at how to do this programmatically.
How do you create two dimensional graphics that move
in response to user's action or to just move
around on the screen on their own.
So this is a translation of sorts.
Moving up down or left or right.
But you can also do in the simulator
if you hold option you'll see
that my cursor flanked by a second circle.
And these represent two fingers.
So you can actually mimic the idea of pinching,
even though you can't touch your laptop screens.
And if we do this, we can zoom
in on Rob's denim shirt atop denim shorts.
And or we can zoom out until this image gets super
super small.
Much like you might pinch or zoom in maps,
or Google Maps or the like.
So, how would we go
about implementing something like this?
Well, let's take a look at some basic building blocks.
And we'll see some similarities and some differences.
This is the more complex of the ones we looked at last time.
So AppDelegate is a good place to start.
Main dot M never seems to have anything of interest,
so we won't even glance there for now.
Does anything look anomalous?
New? Different?
In this file versus past examples?
This is the AppDelegate.h file.
No? Nothing magical there.
This is just a boiler play code that you get
with the single view application.
How about the dot M file if I scroll down.
Looks like this is the only method.
Anything interesting, new or different there?
No. But it seems to be this guy
as usual that's kick starting the process by assigning
to view controller, a newly allocated controller.
It's being initialized with a nib view controller.
There's no file extension, but recall that that's by default
by referring to the dot XIB file that we had for some time now.
And then finally we're making it the key window and visible,
which means foregrounds,
whatever the contents of that nib were.
Well, what is that nib?
Let's take a look in the XIB file and we see Rob.
For a moment in flash, for just a moment,
because that's actually there's a couple
of objects layered on here.
And we can see this by zoom in and I click on view.
Recall that view a UI view is is the rectangular shape
that we typically lay down.
And we have an image view.
So, this is actually a different class
that we haven't seen before.
If I pull over inspectors over here on the right,
and choose my identity inspector,
you'll see that this is a UI image view.
And this is like a container for actual images.
And those images as we'll see in a second are going
to take the form of UI image objects.
So let's actually see how we now started listening
for event atop Rob's single photo there.
Well first, let me expand supporting files.
There is the photo, Rob.jpeg, that I configured here.
And indeed if we go back to the inspector just to confirm,
let me go up to the attributes inspector.
The fact that it says rob.jpeg on the top right corner,
that just means that's why the imagery was displaying
that image.
So no magic there.
So is the complexity must be in this guide, no,
not in the view controller.
H or the one remaining candidate view controller.
M. So let's see if we can't wrap our minds
around what's going on here.
First, a couple of teasers.
So this up here is an example of what?
What object of the construct?
Yes? Yes, so it's a category.
It's a nameless category because there's nothing inside
the parentheses.
And it's a way of sort of creating the illusion of privacy
and objective C whereby we have apparently a private data member
called a CG point underscore translation.
And CG point is actually something
from the core's graphics library.
So CG, core graphics, this is referring to Apple's support
for two dimensional graphics.
And we'll see that this is actually a primitive of sorts.
It's not actually an object because a lot of the code you're
about to see in two dimensional graphics actually has its
origins and seeds.
So we're going to start seeing some commingling of objective C
and C, which is the language they'll call you to look
at when Rob was at the [inaudible] a few weeks back.
So we have a couple of properties in here.
One is a float called scale.
And one is an image view, a UI image view called image view.
And we'll come back to that in just a moment.
We seem to have a couple of private methods here,
one is called handle pan, so moving left to right, up, down.
And handle pinch, which is the two finger gesture.
So that's just setting the stage now to listen for those events.
And if we scroll down here, what seems to be going on?
But when is this yes?
Is there any reason to use an instance variable rather
than a property?
That's a good question.
What was the motivation for this.
You can still do primitive.
Short answer I don't think yes?
Yes, no that's true.
But I'm at the same time not doing the same when it comes
to scale and image view necessarily.
Let me think about why we did this the way it is,
but short answer doesn't matter in this way.
We don't need the functionality of the setter or getter.
Pretty good question.
I'll come back to it.
All right so, in initWithNibName.
This is the first method that's invoked here.
And the ininitWithNibName seems to be preparing a few things.
So one it's calling the super class,
which is actually doing the loading from that.
XIB file, which is the normal default case.
And then we're apparently setting a property called scale
to 1.0.
And that's just a default reminder that by default,
Rob is at normal scale.
A hundred percent X, a hundred percent Y there's no zooming
in or out.
And the translation X
and translation Y is referring oh, this is why.
So, the reason that I'm using the
so CG point is actually something called a C struct,
which you may call it glancing at and see.
And just kind of like an object
that doesn't have methods associated with it.
It's just a data container for data.
So problems actually arise because Apple goes to use the.
Operator when it came to properties.
But the. Operator's is also used for structs.
So doing it this way ensures there's other clarity
as to what's going on.
In this particular line here, that's highlighted in blue,
I'm accessing the X member of the CG point struck.
And I'm doing then the same for Y. So things get a little messy
if you start commingling the two features.
Get back to this.
Okay, so translation X,
translation Y. A translation is just a shifting.
Up, down, left or right or some diagonal.
And this is implying by default.
Rob has not been shifted up, down, left or right.
He's just smack dab in the middle of the screen.
So these are initializations of variables.
So now, a few things are going on.
There's a handle pan method apparently.
There's a handle pinch method.
There's a view did load, let's actually go to view did load
down here and let me hide this
so we can just focus on these three.
View did load recalls loaded, once the nib has been loaded.
The view is ready to go in memory.
And as the common suggest, we're listening for two things.
A pan from left to right, or top to bottom,
or bottom or top, down.
Or a pitch with two fingers.
And this is code quite like we saw last week.
We initialized a certain type of recognizer.
We initialized it with a target that has
to be self in this case.
Self is referring to an object of what type at the moment.
Who is self?
The view controller.
So presumably whatever method, we are telling recognizer
to invoke when panning happens is somewhere in this class.
And indeed it's higher up in the file.
And in this selector syntax is just our way of saying,
call the method handle pan.
And call in just means it takes that one argument.
And then over here, what are we actually doing?
Well, notice that self.
Image view is our property that maps via interfere builder.
I drag and drop the little blue line connecting IB outlet
to my nib.
This is saying, add that recognizer
to that view object on the screen.
So that is the rectangular shape that's going
to listen for this pan gesture.
And pinching, essentially the same thing.
Any questions on how we set that up?
Thinking back that again the structure is the same
as last week.
No? Okay. All right.
So now let's look at the part that does all of the thinking.
So handle pan.
This is where it gets a little complex.
But this is just the result of reading
through what exactly each of these functions does.
A lot of this is again C. And the first thing
that happens here is that we first request
from the UI image view, that container containing the image.
Something called CG point translation.
So this is essentially 0 comma 0 by default.
And then the next line we're making an
AffineTransformMakeScale, which is essentially saying
by how much do you not to grow
or shrink Rob along the X and the Y axis.
And then we go ahead and ask to make a translation.
Translation refers to by how much you want to shift Rob,
to the right, to the left, up or down or along some diagonal
by adding those two axes together.
And then lastly, this last line
of code actually applies that transformation.
That changing in scale, bigger or small sand that shifting, up,
down, left or right to whatever the object is,
which is again, that UI image view.
So, those several lines of code which are
at each point essentially declaring a C struck.
The C struck a C struck that's being populated
by the return values of these functions
on the right hand side.
They're then being applied in this final line.
So what is the role played by these last few lines down here?
Why are we not done as soon as we we apply the transformation?
Yes?
[ Inaudible ]
Exactly. Good.
Because we're doing some additive math,
especially when it comes to the translation, we're taking
into account where Rob began on the entire screen.
So if we wanted him to not snap back
to the default location each time you drag or drop him,
we have to simply update those local instance variables.
Yes?
[ Inaudible ]
Good question.
It does expire several times otherwise if when I clicked
on Rob's face, I'll be in a simulator there.
You wouldn't have seen anything happened until I let go.
So it does fire at a particularly fast frequency
so that you can respond essentially pixel by pixel.
Good question.
Yes? You can change the rates.
The default is set by default but you can override it
so you can respond in different ways.
Much like the long press.
By default, it roughly two seconds before Rob's face would
have triggered that UI alert view last week.
And that too you can raise or lower programmatically
when declaring the gesture recognizer.
Good question.
Yes? Uh huh, say that again?
So we're called, these are not IB action.
So IB actions are how we declare methods inside of a class
when we want objects inside of a nib to talk back at them
or more generally for UI views to talk back at them
when a user interacts with them.
In this case, it's the gesture recognizer, which is a class
that Apple has provided with us.
That is responsible for invoking this methods.
So it's not quite the same use case
because these messages are being passed by this recognizer class.
[Inaudible] in IB outlet property.
So typically, if you want to connect your code
to an interfere that you created with interfere builder
in a. XIB file, then yes, you do exactly that.
And that is the reason why we scroll up to the part
that we glossed over earlier.
I have two things declared as properties.
One is is the scale, which as we'll see is just a way
of remembering when I pinch,
what the scale factor is for Rob.
If it's not 1.0 by default in image view is very typical.
Notice, that we have IB outlet here.
And we see this in a number of examples in past weeks.
This is my mechanism for actually linking my code
to the UI image view so that I can actually apply
that recognizer and listen for those finger touches.
Good question.
So, pinching is going to be pretty much similar in spirit,
even though some
of the functions calls will be a little bit different.
Let me scroll this over just a bit.
And handle pinch is method that's going to get invoked
when you're using the two finger
to go separate or closer together.
And now we have this first.
I'm declaring a CG float struck.
So again, here too, it looks like a class.
It it looks like an object thereof.
But this is again just capitalized to be consistent
with Apple's tradition for C [inaudible] structures.
This is a CG float, which is just some representation
of some floating point value.
CG affine transform scale is doing a line of code similar
to before where we take the current scale
and multiply it by some factor.
And notice that the factor has been passed in to us.
So one of the things this recognizer does is it figures
out how far away did your fingers move
in that split second of time.
And then it forms this method what that difference is
so that you can scale accordingly.
Then if we looked down here we're doing a translation.
This time we're not actually moving Rob
because we're we only want to move Rob when we're panning,
not when we're pinching.
So he's going to stay put but grow
from wherever my fingers are moving closer
or farther away from each other.
And then we apply these two things again much
like we did previously.
And then lastly, all we do is remember that change in scale
so that when I do it again, he doesn't snap back
to the default 1.0 resolution to start anew.
All right, any questions then?
So we've seen some buildings blocks now for swiping, up,
down, left, right for touching, for pinching,
for clicking and dragging.
And so, with those, for your third project, if you choose
to do something in iOS
that actually has UI interactions beyond what's
possible out of the box with interfere builder,
realize that these are the basic building blocks.
Even for say, a simple game.
We'll put these to the test later tonight
when we implement an age old games of sorts.
All right.
And you might see [inaudible] to right there.
All right.
So, questions on the basics of graphics before we move
onto things that are useful to have in your tool kit.
But then we'll come back full circle to the application
of two dimensional graphics Actually moving on their own
without human interaction.
Okay, so a design question then.
So, totally changing years for just a moment.
And localization refers to what process when writing code?
Okay, internationalization.
So not just naively assuming that everyone
of your users is going to speak English and read English
but rather might have some other native tongue.
And you might want to cater to that audience
that actually download your user app, can understand your app.
Whatever the reasons.
But this is problematic because we've gotten
to the habit thus far of writing quite a lot of code.
And what's essentially English, since Apple came from the U.S.
but also, quite a lot of strings.
Quite a lot of NS strings inside of double quotes.
Maybe prefix with an at sign.
So this is kind of problematic.
Because I feel like if I want to suddenly support Mandarin
or Spanish or any other language to which I might want
to localize high application,
now I have to do a whole lot of copy paste.
And any file that has a quoted string, like hello world,
I'm going to apparently need to copy my view controller.
H and maybe make a separate one for each language.
View controller.
M, a separate one for the languages.
Like, surely, this isn't the way.
Because if there's some 50, 60 languages you might even want
to support, I mean, that's a nightmare to have
that much code lying around.
If only because now if you want to make a change,
you have to make it in dozens of places.
So what's a smarter approach?
And let me [inaudible] this
with someone who's never internationalized an
application before.
How would you go about solving this problem?
All right.
[ Background Discussion ]
Yes. So that's exactly right.
But the principal that I'll highlight there is the fact
that you're proposing that we factor out the strain.
So you could write all of your code in English
or pseudo English, an objective C or C,
whatever the language is.
But if you at least factor out the strains that have
to change based on the users end language by putting them
in some central file, now you can keep separate your codes,
your business logic so to speak from your actual data,
in this case, the streams that the user sees.
So, you're indeed right, the way Apple typically does this
for desktop or iOS applications is that you have a P list file,
which is just an XML file underneath the hood.
But so far as we care, it's just a text file
that we can therefore edit.
And if we have after separate file for English,
a separate file for Mandarin, a separate file for Spanish,
we can essentially tell iOS, the operating system,
depending on what language the user's iPhone or iPad is in,
load the appropriate key list file for me.
So, in fact, you've seen a few different things.
We'll use a file that typically ends in dot strains.
But it's the same exact idea.
It's even simpler than a P list and that we just write things
in the form of text, no XML whatsoever.
So, let's go ahead and do an example here.
Let me open up X code.
Create a new project, which we'll do a single view.
Let me then proceed to name this, let's say, Hola 1.
I will bias things toward English and Spanish for now.
I'm going to go ahead and leave automatic reference
counting checked.
I'm going to leave everything else unchecked.
I'm going to go ahead and click next.
I'm going to go ahead and save this on my desktop
and now I have the simplest of applications, which will call
if I run it, just gives me a big white box in the form
of an application that looks like this.
So very underwhelming.
But let's make it a little sexier
by going into the nib file.
Let me go ahead and drag a label into the middle just
so I could support iPhone four and iPhone 5's.
Let me go ahead and click down here
if you haven't noticed this control bar,
and turn on a constraint called vertical center.
This will ensure that whatever simulator you're using
or whatever device you're using,
at least this text will be vertically centered.
And by default, let me just go ahead
and make the American centric version hello world.
All right.
So now notice what I have on the left hand side of my screen.
All of the familiar files.
The program happens to be called Hola, but that's just
because I wrote that and nothing has been actually been
internationalized yet.
But those are all pretty much familiar files.
And particular notice there's just a single nib file.
But if I now want to localize this application,
we can do the following.
And unfortunately this feature changes location
with every version of X code it seems.
But if I go ahead and click on the project on the top left,
then click on the project to the right of that, you'll notice
down here that there's a screen in related to localization,
a.k.a. internationalization.
And if I go ahead and click the plus here, I have a whole bunch
of languages that X code supports nicely right
out of the box.
I'm going to go ahead and choose Spanish.
And if I zoom out I'm now being prompted
to do a couple of things.
Choose files and reference language
to create Spanish localization.
So it turns out that by default, there's two different files
that can take on some other language.
One is the nib file apparently.
And one is a file called InfoPList.strings.
So, I'm not going to touch the latter just yet.
I'm going to uncheck it and come back to that.
But I am going to tell X code to localize my nib file.
So if I go down here to finish,
what I now get is both English and Spanish.
And if I go back to my nib, notice that by default,
I still see hello world but notice what's different
about the nib on the top left.
Yes, it looks like its become a hierarchy of some sort.
If I expand this triangle, I seem to have English,
which is what I had a moment ago.
And then I have Spanish, which is apparently the same.
Okay, so it actually hasn't done any translation for me.
That's sort of human to actually do.
But I can go into this nib now
and I can say something like, hola, mundo.
Change it there.
Save it, and now I have my English version
and my Spanish version.
So let's see what now happens.
I'm going to go back to the simulator.
Or rather let me go ahead
and [inaudible] the simulator by running the code.
Its been built.
It's being installed into the simulator.
And when it comes
to the foreground we should see hello world.
Now, let me disclaim.
About every 5th time I try this
on different computers, it doesn't work.
So if it blows up, realize that I've should a disclaimer,
which means it's okay.
But if I now go here, these are just all the applications we've
been installing in recent weeks.
I'm going to right click over to the settings.
And if you've never done this on your phone or iPad,
you can go to general international language.
And I'm going to choose Espanol for Spanish.
Done. It's going to change language dot dot dot.
The next code is going to crash because it doesn't like it
when you do that when it's still running.
But I'm going to go ahead now and rerun the simulator.
And now we have a Spanish version of the application.
So the only thing that's changed, crash aside,
is that I changed the settings in my application
to actually be, Spanish instead of English.
And if I went back to English,
you should hopefully see hello world instead.
But a couple of things haven't changed.
In particular, what's the name of this application apparently.
So it's still Hola 1.
So irrespective of the language, my phone is configured
with the application, which is still the same.
And maybe that's a good thing.
Maybe you want the game
to be called Angry Birds no matter what the language is
actually is.
Or maybe you want to localize that too.
So you can do that in different places.
So let me actually go ahead and open
up a second example here whereby we start fresh,
single view application, Hola 2, will be this application.
And save it on the desktop.
And let's do something that's almost the same
but this time I want to do a little bit more in code.
So I'm going to go ahead and open up my nib file.
This time I'm going to drag my label.
And I'm not going to hard code it into my nib.
Because we're called that if we do a little bit more
programming, we can actually control
that label programmatically from code.
So if I want to do this let me make sure things line
up with the online codes so that you can play along
at home after.
If I want to actually do this, what's the first thing I need
to do to wire my code up to my nib file?
So all I have is the empty boiler play code thus far.
Yes? Okay, so I need to create an IB outlet,
which likely belongs in what file?
Okay. So, somewhere in the ViewController.
And early on we're called that we put almost all
of our properties, just by convention,
into the dotted H file.
But then gradually last week we started moving more and more
of our properties and method declarations
into the dot M file.
The implementation file, just because there's really no reason
to inform the whole world what our private implementation
details are.
So I'll go ahead and open up ViewController dot M.
And I can implement this inside of my nameless category.
So I'm going to declare a property with a view attributes.
But we will come back to that.
It's going to be a UI label and I'll just call this label.
Now I need a couple of more things.
If this is going to be an IB outlet, I need to say IB outlet.
And what attributes would be appropriate
for this outlet, for this IB outlet?
Well, one is always easy.
We haven't seen atomic, so non atomic, I think is fine.
We're not writing multi-threaded code out here
within this application.
Read only or read write.
The goal is to recreate the hello world application
by this time in code telling it what to say.
Either hello world or hola mundo.
Okay, so read write since I want to be able
to change what it's pointing at.
And then lastly, I can actually go with week.
So we haven't spent too much time on this but we're called
that strong versus weak somehow relates
to how the pointers are going to be dealt with.
And in this case, weak suffices
because all I need is a pointer to a UI label.
But I'm not the owner of that UI label per se.
The owner is really the nib file.
And when the nib is loaded, it will take care of [inaudible].
That the ram that's necessary to store that label
on the screen will be allocated by it.
I am just some other guy, ViewController.m,
that similarly wants to talk to that pointer
but it's not really mine per se, so weak suffices.
Someone else owns it.
I did not instantiate it myself.
It came from the nib.
So after this, I now have programmatic access
to the label.
So what do I want to do?
Well, I want to get rid
of the [inaudible] receive memory warning.
There's not much we can do if this application runs
out of memory because there's terribly little going on,
just that UI label.
And I am going to put some additional code
into viewDidLoad.
First, again by convention,
I'm going to call the parent classes, viewDidLoad method,
whatever that happens to do.
And when this view load so when the nib is loaded from disk,
and the rectangle is constructed,
and that UI label is placed in the middle of the screen.
And I want to do one configuration detail, namely,
self.label.text is what's actually inside of that label.
Is going to get.
And this is the new part, NSLocalizedString.
And now according to X codes prompts here,
it wants a key and or a comment.
So I somehow need to provide it
with an identifier for that string.
It doesn't want me to put, for instance, hello world, per se.
But rather a generic key that's going to be defined
in two different places, two separate files,
so that I can look up that value dynamically.
So, comment, I'm going to actually leave nil.
Comment is just for really the humans doing the translations.
You can use tools to automatically generate a file.
We are about to generate manually, so that if you
or the programmer, who maybe only speaks English,
but you want to tell other developers
who actually speak multiple languages,
what this string represents.
You can do it in the form of after comment there.
So that when they automatically generate the file we're
about to generate manually, they know what you mean by that key.
So I'm going to choose something arbitrary
but sensible, like, greeting.
So quote on quote greeting, is not what I want the user to see.
It's just going to be a key into a table of strings.
So to create this I'm going to go up to file, new, file.
And we haven't seen this one before, but if you poke around,
you'll start seeing some other useful things.
If I go to resource, notice there's a few resources here.
Property list, we've seen before.
Strings file is another.
And according to the description,
it is an empty strings file.
It's just a text file.
So let's go ahead and click next.
By default, I'm going to call this Localizable.strings.
And X code knows by default to look for file by that name.
And if it's present, go ahead and allow the user
to just find multiple languages strings in there.
So I click the create.
And now I have this text file over on the left hand side.
Notice that there is just some generic comments at the top.
And it's in here where I can now define some key value pairs.
All right?
So now, if I want to go ahead and define the key value pair,
let's go ahead and define what greeting has to map to what.
Hello world or hola mundo.
And then we're going to need to do that not in the same file
but in two different places.
So before we do that, let me go
up to my project settings as before.
Hola two is the project.
And let me go ahead and add proactively, Spanish.
Unfortunately by default, X code only seems to know
about these two default files.
ViewController.nib and InfoPList.strings.
We're not doing anything with the nib this time.
So just to keep things clean, I'm going to uncheck that.
InfoPList.strings we'll come back to.
And now I have Spanish language.
But unfortunately, I haven't solved the problem at hand.
And this is just an [inaudible] UI decision.
Notice on the right hand side here,
if you want to localize a .strings file
that I have created myself manually, unfortunately you have
to click this big button called localize.
And here's where I'll be prompted, oh,
do I want to localize this file into which language?
Spanish. Now we'll go ahead and localize.
And now that did not behave oh, there it is.
By default, X code does not check both boxes.
So if we now check English and now go over here on the left,
Localizable.strings has both English and Spanish forms.
So if we fast forward now to the climax of this example,
what we'll see is an example
that has both the Spanish version
and the English version exactly as follows.
In Hola two, we have supporting files.
And if we go to Localizable.strings,
specifically the English one, notice that again,
this is just a mapping of keys to values.
Quote on quote greetings equals quote on quote hello world.
Notice that it's not an NS string.
These are C style strings now, so there's no
at science involved in this file.
But they do end with a semicolon at the end.
If I go to the Spanish version, the key is the same,
so you don't localize that.
But the value does change.
And so, because this file is called Localizable.strings,
iOS will load it automatically for you and use
that when you call the function that we did earlier,
called NS localize string.
And there's one last thing I did here in advance.
In this file, which to date, we have not actually looked at.
InfoPList.strings.
According to the documents, if you define a key,
called CFBundleDisplayName, you can also change the name
of your application programmatically.
So in this case, I want my application to be called Hola.
But if the user is English speaking,
I want it to be called Hello.
So no more Hola one, Hola two.
This is the formal name for my application.
If I go ahead and run this, I'm still in the simulator here.
So we should see now the second version of this code.
Hola mundo.
And if I now go back to the desktop and take a look
at the program's name, it's Hola.
If I go back to English, that's changed to Hello,
and the string should go to Hello world.
So, sort of lesson learned here, especially if you're planning
to do something for the app store.
And you actually do want to appeal to multiple languages,
this is the sort of thing where it's good
to start designing your strings file now so that you don't,
after writing 2,000 lines of code, have to go back in
and then start ripping things out
and redefining key value pairs.
If this isn't a problem, if you have no expectation
of localizing, not a big deal.
But it is this easy.
And it's a lot easier to do it in the beginning,
even if you just have a Localizable.string
with only English.
Because just think how trivial it is if you make a friend
who speaks Spanish and he
or she can then translate your whole app for you just
by your sending him or her that text file to send back to you,
the importance of a project.
Yes?
[ Background Discussion ]
Ah, good question.
By default there's still one primary language.
In this case it's English
because that's what I started with.
So what would happen is that you would get the English version
by default.
If the user has chosen some other language
that your app doesn't explicitly support.
[ Background Discussion ]
Good question.
Most likely.
If Mac OS is configured for Dutch and therefore X code is
as well when you download it from the Dutch app store,
I believe that's what will happen.
But I've not had occasion to test that.
Other questions?
All right.
So, where can we take things from here?
So I propose that from here there's a couple
of gaps we can fill in before moving onto the climax.
Albeit a 1980's climax of a two dimensional game.
But sequel lites.
Let's add one other tool to your tool kit.
What would sequel lite all about?
Okay, good.
So it's a flat file relational database.
So this is just a fancy way of saying,
there's no server involved.
There's just a big binary file
that can sit inside of your application.
That can create the illusion of a database to your application,
namely a sequel database.
And a sequel database allows you to do searches
and queries along the lines of select and insert
and delete and update.
And even if you're not familiar with that,
those four letters together compose a paradigm called CRUD.
C R U D for create, read, update, delete.
Which is a very common paradigm for talking to a database
which essentially lets you do anything.
You can read from it.
You can write to it.
You can update things, you can delete things,
you can store data in we write fashion.
So why would you care to use sequel in this database language
as opposed to just using a P list, like we've been using
for the second project.
Or even .strings file, you just have a list of strings
or some other file format altogether.
Speed? In what sense?
[ Background Discussion ]
For sure. Certainly for large data sets
for you have thousands, tens of thousands,
hundreds of thousands of records.
If you stored it in a P list, well,
by default that's just an XML file.
So really, it's just a big long list.
So if you were to do searches on a property list,
you essentially devolve into linear search.
And in an worst case, maybe the structure you're looking
for in the dictionary is at the end of that P list file.
So it's going to take you thousands or tens of thousands
of reads in order to find the word you're looking for.
By contrast, if you use an actual database,
whether it's my sequel or oracle in the real world,
or sequel lite in a constrained environment like this,
you can say something like, select the word that starts
with Z. So I'm using sort of pseudo code verbally.
But you can express yourself more precisely.
Select the word that starts with Z and what sequel lite can do
for you, if you tell it in advance, is it can give you,
what are called, indexs.
Essentially, tree structures that have been saved
to this file that once loaded into memory,
allowed you to search this file much faster
than say linear search would allow you to do.
So at least for large data sets, it allows you
to express yourself a little bit more precisely
than just iterating over a big list of things.
And to get that data more quickly.
Unfortunately, for those of you who are familiar with sequel,
the price you pay is in shear complexity of the codes.
Since to date, it's still a C library, which is a pain
in the neck to use when doing something
as simple as we just described.
But nonetheless, so that you have this expressive capability
at your disposal, particularly for your third project
of doing something with a decent sized data set,
let's take a look at this example, called sequel lite
from tonight's code base.
AppDelegate look special?
No, nothing new there.
AppDelegate.m, anything going on here?
Nothing there.
So hopefully the interesting stuff starts
in the nib file, okay.
So, apparently this app has to do with cities.
Known as just again, stupid boiler plate patterns
of any UI table ViewController.
So, this just means the application has a table
ViewController, and let's actually spoil the results.
Let me go ahead and run this application
and see what happens inside of the simulator.
And what we can see here in the simulator is
that all this application does is it opens the contents
of a sequel lite database called small.sqlite,
as we'll see shortly.
And it lists those five words.
From the small P list file that we gave you
for the most recent project.
So what I did in advance was I wrote a little script
that converted that property list file
into a binary sequel lite file.
It's pretty easy to do.
And then I included the small.sqlite file inside
of the project by just dragging and dropping it from my desktop.
So, how is this actually behaving in this way?
Well, let's take a look
at ViewController.h. Nothing going on there.
So all the logic must be in ViewController.m. So,
first of all, notice that I've declared an NSMutableArray
as a property called words.
And this is just where I'm going to store my words
when actually using them.
Much like you probably have for evil hang man
after you've loaded the property list.
And if I scroll down here, let me get rid of one remnant there.
I have in initWithNibName.
And this is where the nightmare begins.
So, and I say this, because it's just a pain in the neck
to actually code sequel queries in this way.
But, this is the way it is, not only in objective C
but in some other environment as well to this day.
So, notice I'm first initializing myself
with the nib name.
Whatever that was, by calling the parent class.
Then I'm declaring an NSMutableArray here
and assigning it to my property.
So I just have an empty changeable array.
And now, what am I doing in English or sort
of semi technical English with this highlighted line.
What's apparently going on there,
even if you've never used sequel lite before?
Yes. Good.
So I'm creating a pointer called DB
to an object of type sequel lite.
Whatever that happens to be.
It's some kind of structure presumably.
And then in that next line, notice I'm going back
into objective C mode.
The highlighted line is effectively C.
So here I'm declaring a path variable that's the result
of looking for the file called small of type sequel lites.
So this is just a fairly robust way of saying, give me the path
to the file called small.sqlite.
And notice over here on the left, that's the file I promised
that I dragged and dropped into the project.
It's a binary file.
So clicking on it won't actually show me the contents.
Now here, is a bit of syntax.
We haven't seen too much.
But you might recall from Rob's lecture a few weeks back.
Sqlite3_open is a C function
that opens a database connection.
So, database, notice that path is of what data type
in this point of the story?
It's an NS string.
But sqlite3_open, perhaps take my word for it, is a C function
that has no concept of objective C classes of observe.
So we essentially have to convert path from an NS string
to what's called, what most people call a char star.
A raw C style string which is just the dress
of a bunch of character.
A character array.
And so what this line is doing is exactly that.
It's opening the file call that's at that path
and storing it inside of the DB pointer.
Okay? What's happening next?
I'm selecting all words.
So, this is what I meant earlier about the expressiveness.
This is a sequel query.
And this file at the end is only going to have one such query.
But again there's other key words like delete, update,
insert, any others, select is the operative word here.
Here I'm declaring an NS string called sequel.
In the next line, I'm dropping back down into C,
declaring a statement.
And then in this third line I'm calling sqlite3_prepare_v2.
This is what happens when you overall plan your functions
ahead and names get like this.
And then I'm passing in a few values.
Again, converting from a C an objective C style object
to a C style string.
And let me wave my hand at some of the details there.
But what this just means is get ready
to execute the previously declared query.
Select star from select word from words.
So what is words?
Words, again, is the database.
Or specifically, it's a table inside of the database.
Like an excel spread sheet.
And word, specifically, is is one such column
from that spread sheet.
So this is a super simple database.
It essentially is an excel file
with a single column A, if you will.
And column A is called just because I named it such word.
So it's not even that interesting of a database.
Yes?
[ Background Discussion ]
Exactly. So you don't strictly need
to specify the database name.
You don't need to say database.table
if it's obvious from the context.
And in this case, you can infer it from the context
because when we open the connection,
we open the connection to a specific database.
So that part has already
that question has already been answered for the library.
So now down here is where we are actually fetching data.
So by calling sqlite3_step, passing in that statement
that I've prepared in the previous line,
If that equals SQLITE_ROW so, in other words,
if that function returns to [inaudible] row in the form
of a structure, I can then proceed to do the following.
This next line of code gets the 0th column or the 0 cell
from that 0th column from that return cell.
And then in this next one, I convert the string
that I've gotten back to what kind of object?
So in NS string.
And then the last line, I'm finally back
to more familiar territory.
I'm adding that string to my property,
which is a NSMutableArray called words.
So again, the difference here, for those less familiar
with C is that in C there is no notion of an object.
There is no notion of a class.
It's not an object oriented language.
So to implement the idea of a string,
what C does is it uses an array.
So, a chunk, chunk, chunk, chunk, chunk of memory.
And then to represent the string, it uses a back slash N,
a null character at the end of the string.
And then it gives to you the address of the first character.
So in C, if you know the address of the first character,
and you know that there's guaranteed
to be a null character at the end of the string,
you can figure out how long it that string is
and what the word being expressed actually is.
[Inaudible] where whatever it is in the database.
Objective C by contrast using classes and objects.
So maybe that's how a string,
an NS string is implemented underneath the hood,
we just don't know.
So what these several lines
of code are doing ultimately is toggling back
between these modes so as to use the C base sequel lite library,
while still using it in objective C context.
And then lastly, that we close the database connection.
And the rest of the code here which we won't trace
through in any detail, is pretty much the same as last week.
The rest of the code just has to do with the UI table view
and somehow defining the cells that you see
when asked what goes in row 0.
What goes in row one.
What goes in row two and so forth.
But there's one thing I had to do behind the scenes.
Recall that for quite some time under frame works,
we had just UIKit.framework, foundation.framework,
CoreGraphics.framework, which we finally started using tonight.
Notice that in supporting files, there's something similar
in spirit, but it's a C library.
So it's called a dynamic library.
Sqllib sqlite3.dylib.
This is a file that I did not drag and drop
into may project per se.
Rather, in order to use this library,
and potentially any other libraries that Apple provides,
I went into my target.
Went to build phases.
Went to link binary.
And here is where you see the list of libraries
that your application is using.
By default, we've always gotten those three objective
C libraries.
Today I needed a fourth library, mainly the sequel lite library.
So to get there, I had to click that plus icon and then look
through a list of libraries.
And you'll see there's an overwhelming number of options.
Suggested of how much more you can do with the environment.
If you really dive in deeper, this happens
to be a C based library.
And what do you think is inside of this library?
What is the point of adding this row to this configuration table?
I wrote Sqlite earlier, right?
I wrote the various function calls.
Why do I need to add something like this?
What must be inside there?
What's that?
All the function definitions, so the actual implementations.
The only thing I had to do even though we glossed
over it earlier, is in my ViewController.m file,
I did import this .h file,
but in a .h file is not the implementation of some function.
And typically is in some other file.
So, if I actually want the bits, the 0's and 1's,
that collectively compose the Sqlite statement query,
the close query, the open query I need
to actually import those bits at link time so to speak.
And the means by which you do
that in X code is via the project's own properties
under build phases.
So, FYI. Yes?
[ Background Discussion ]
Short answer not as cleanly as would be ideal.
Rather there's an even higher of layer
of abstraction called core data,
which is actually a pretty raw topic onto itself.
But it's essentially an abstraction layer
on top of sequel.
Or it can be on top of something else potentially that allows you
to define your entities and your relations without going
into the depths of sequel.
All of that would be generated for you.
So, short answer no.
No wrapper in objective C rather apple leap frogged
and went one level higher.
Quite possibly.
Yes. I've not used one, but there's not one that comes
out of the box officially.
Good question.
So wonderfully useful, but also takes some getting use to.
So, keep that in mind.
But much more powerful than something
like the single key list file.
So let me open up a little teaser here.
Some of you may recall or have at least heard of a little game,
that for many years was amazing.
And it looked like this.
Let me go ahead and run this.
I'm going to put the iPhone into a landscape mode this time.
And notice that the computer is playing on the left.
And the human, I'm playing, on the right.
By moving the cursor or my finger, really, up and down.
If I do this, I can do this all day long.
This will just play and play until I do something stupid,
whereby if I forget to move, now he has the points.
So, why don't we go ahead and take our five minute break.
I really lost fast there.
Why don't we take our five minute break here
and when we come back we will implement pong together.
All right, so first let's resume by lowering expectations.
This is an example called paddle,
which is among tonight's examples,
whose sole purpose is to do this.
But it's a good building block if we actually want to get
to the point of actually having a bit of AI, if you will.
You'll notice if you play the pong game as its been written,
the computer will never ever lose.
Because it will see the code is written in such a way
that the paddle always move to precisely
where the ball is no matter where you hit it.
So, only the human can lose that game.
But, we'll start by at least making our own paddle here.
The cursor there on the screen is what my finger would be
if we weren't doing this in the simulator.
But first, we need a little bit of context.
So let me switch over here for just a moment.
Just to paint a picture of how your mental model should be
when it comes to graphics.
So, correspond graphics is the context.
We've seen this library included
for every example we've done thus far.
But this is the first night where we're actually using it.
And what's worth keeping in mind is this system got to get better
at this this coordinate system here.
So I looked for newer image, but even Apple documentation uses
like the iPhone three for this example.
But it's really just to paint a picture
of the coordinate system in iOS.
Which is this plain, where we have X coordinates on the right,
Y coordinates on the vertical.
And this is just the take away here is
that the coordinate system begins
on the top left hand corners.
So, ten comma ten means ten over and ten down.
Not the opposite as you might know
from say typical [inaudible] coordinates and algebra.
So, the catch is as Apple's hardware has advanced over time,
that resolution have started to change, right?
There was the retina display and the iPhone four,
when the resolution essentially doubled.
And unfortunately, this could have broken a whole lot
of applications.
But Apple actually anticipated something like this in the sense
that you don't think of graphics in the two dimensional world
of iOS as pixels, but instead as points.
And a point is still just a dot.
But it might be one pixel, or maybe it's four pixels.
It depends on your perspective.
So they introduce this layer of abstraction called points.
So that you're respective of the actual resolution.
The operating system will double your graphics as needed
or shrink them as needed.
Now this has it's a two edge sword.
It's on the one hand, super convenient, on the other hand
if you've ever used an IO an iPhone only application
on an iPad, it just looks kind of ridiculous when you zoom
in at two X. But that's really the only alternative would be
to not let the user play it at all.
So now if we scroll over to this system here,
you'll see the iPhone four and the iPhone five.
So the annoying thing here is
that Apple didn't just double the resolution, they just kind
of stretched it a little bit.
So there were a few more pixels now on the screen.
So this was more problematic.
And there's still some apps out there that you might have
on your own phones that now have letter boxing on the bottom
or on the top with just black bars.
If you have an iPhone five
and you're using somewhat older software
that the developers hadn't updated.
So in this case, the number of points
on the screen has actually changed.
It's still 320 pixels across,
but it's now 568 tall instead of 480 tall.
So this is why Apple,
as in aside introduced something called auto layout
with the most recent version of X code.
And we saw me use it ever so briefly earlier.
When I said to vertically center the label that I dragged
and dropped by choosing a vertical constraint.
This is the new means by which you can essentially lay things
out dynamically.
Unfortunately it doesn't quite work as easily.
If you're implementing something like Angry Birds
or something graphical where there's a pixel precision
when it comes to your graphics.
So some people actually have
to use different graphics for different modes.
And that's why we started
to see more [inaudible] among the supporting files
and all the projects.
One is a bigger splash screen.
One is a smaller splash screen depending
on the device that someone's using.
So it's starting to get a little more android
like in its new sense.
So we'll see what happens next with the iPad, which is like,
would become, right now before long as well
at a higher resolution.
All right.
So how do we go about implementing something.
It's relatively straight forward as this.
There's some new ingredients.
But what are some now familiar ingredients if we want
to implement something like this?
What concepts or code can we steal from recent examples
to implement this paddle?
The sole purpose in life is to go up and down.
Yes? Yes, so maybe a pan gesture recognizer
so that we can actually detect the user moving his
or her finger up or down in this case.
And just ignore their finger
if it moves along the left right axis.
All right.
So, let's take a look at how this begins.
AppDelegate?
Same as usual.
AppDelegate.m, same as usual.
So, no magic there.
So everything must be going on in interesting.
I have a new file altogether this time.
A pair of files called PaddleView.h,
PaddleView.m. Let's take a look at the H file first
to see what this class is.
And it looks actually pretty trivial.
So I'm just importing new UI kit, which is pretty typical.
And then I'm declaring a class called paddle view.
And it's of type of UI view.
So this is the first time we've actually declared
in code our own UI views.
We've had UI view controllers, map main ViewController,
flip side ViewController, ViewController.
But we've not declared our own UI views.
To date, where of our UI views come from?
Often the nib file.
By dragging and dropping.
And in our no nib example, a couple of weeks ago,
we did instantiate UI view objects ourselves
in code manually.
But even those were Apple's own UI views.
UI button and the UI text field.
So this is the first time where we are defining our own view.
Because Apple iOS doesn't come with a white rectangular paddle.
So we have to create that somehow ourselves.
So the means by which we've done this
in the .m file is fairly simply by taking advantage of a method
that is called automatically,
whenever a UI view object is instantiated.
This is essentially an analog of like viewDidLoad.
But that's at the UI ViewController level.
Now we're at a lower level at the UI view level.
So draw rect for draw rectangle is what's called when it's time
to initialize one of those little widgets
that we've thus far been dragging and dropping.
So here again, we're commingling some C code
and some objective C. CGRect is the name
of a core graphics rectangle, which is a C struck.
A container with just data.
No methods.
I'm going to call this square.
And on the right hand side we have a function called
CGRectMake which just returns a C structure.
So a container with a few fields.
And those fields are apparently four in number.
The first two are going to be initialized as 0.
Third is 10.0.
And the last is 60.0.
Any guesses as to what those numbers are referring to?
Close. Not color, in this case.
But dimensions.
And one other detail the XY the initial placement of this thing.
So, 0 comma 0 is just implying
that it's not going to be offset at all.
It's just going to be in the top corner
of whatever rectangle we're creating.
The width is going to be ten points.
And the height of it is going to be 60 points.
All right?
But that's not enough.
Now we've just created essentially a
rectangular widget.
Something that could be if Apple really liked our paddle, dragged
and dropped in some future version of X code, right?
That's really all we've done here.
But there's more complexity certainly
for something like the UI button.
But now let's see how we use this.
In my ViewController.nib,
notice I've done nothing except change the orientation.
So if I actually click on that thing and go
to the attributes inspector, one of those various check boxes
and drop down menus would let me change
from portrait to landscape mode.
And that's the only change I made in addition
to then changing the background color
from that default of gray to black.
So this is going to be my game board, so to speak.
But if I now go to ViewController.h,
nothing interesting in there.
So the remaining magic must be in here.
So notice inside of my ViewController,
I'm declaring a property that's of type paddle view.
Which is my own class that I created.
And it's going to be called PaddleView.
Lower case P, capital V. Now let's take one step
back quickly.
Where did PaddleView.h and .m come from?
Well, we haven't done this that often.
And we did do it earlier with the strings file.
Earlier when creating this, I went to new, file,
and then I just went up to [inaudible] touch.
And started with an objective C class.
Went to new.
The class name I gave it was PaddleView.
And I didn't have to send it from NS object.
I had it to send from UI view.
When I hit enter earlier, I got those two files for free.
And that's when I dove in and then began
to implement DrawRect.
All right, so now, in this file, we have a few methods.
In initWithNibName.
And this looks pretty familiar except
for some new core graphics code.
So in initWithNibName is again what's called as soon
as the nib is loaded from disk.
But that nib by default is just rotated
in landscape mode and painted black.
Now I want to do one other thing to it.
Self.PaddleView, means assign to my property what?
The result of allocating a PaddleView object
and initializing it with a frame.
So here there's a bit of a dichotomy.
Now I am initializing this PaddleView object
to be inside of a canvas.
So whereas before, if you're familiar with Photoshop,
I created like an image.
Now I'm creating the canvas on which to place that image.
So, the image can be offset in the canvas itself.
The canvas can be bigger.
And in this case, the canvas is going to have this image view,
this PaddleView placed on it ten pixels to the right.
Ten pixels down.
And then the width of this over lay is going to be
as we'd expect, ten pick else sorry,
not pixels points wide and 60 points tall.
So what does that mean in real terms?
This is why when we start this thing let me quit
this simulator.
So if [inaudible] familiar, we can double tap there.
Click it how old.
Quit paddle.
Or you can just click stop.
And then you can hit run again to rerun this thing.
Notice that it starts in the top left hand corner.
But the projector is kind of the contrast isn't great.
Take my word for it that that paddle is not truly
in the top left hand corner of the iPhone.
It's instead ten pixels down, ten pixels over.
So in itself is with respect to itself
in its own top left hand corner.
But that's just because the image itself was only ten by 60.
Now we're painting it on the canvas
by offsetting at ten by ten.
And why? I just thought it looked marginally prettier
to offset it slightly from the edge of the phone.
No other reason.
All right, so if we now go back into the ViewController.m,
what more is happening here?
This line of code, addSubview.
We've not done this before.
But we've kind of felt the results of the line
of code like this before.
So thus far when we've dragged and dropped things like buttons
and text fields and sliders from that little menu
and interface builder and dropped it,
we've been adding a view on top of another.
In other words, adding a sub view.
This is the corresponding line of code to dragging
and dropping in that interface.
I'm taking my paddle and laying it on top
of the game board itself.
Which is just that big black rectangle by the default.
Okay. So now, turns out, making this super simple and kind
of pointless game is as simple
as implementing the touchesMoved method.
So the touchesMoved method is a little different
from the pan gesture of recognizer
that we implemented earlier.
TouchesMoved actually allows you to dissect all sorts
of touches on the screen.
Multiple fingers, touches on different locations.
And it turns out, this actually makes it even easier to respond
to those key presses that we could have done this
in different ways.
So touchesMoved is going
to be fired anytime a UI view is touched on the screen.
And what's going to happen here is this.
When this method, touchesMoved is called,
actually the method is called touchesMoved with event.
I first ask the event that I've been passed
as my second argument, give me all of the touches
and then give me any object.
This essentially gives me in this case, the only object
that could have been touched.
If there had been a whole lot of things on top of one another,
it's possible that multiple things would have been touched
because of the various Z axis, so to speak.
But in this case, there's only one paddle on the screen.
So I only care to get whatever is in that set.
So any object will do.
I then with this line of code ask it for its location.
What are its XY coordinates essentially.
And I store those in something called a CGPoint.
A CGPoint is just a [inaudible] X comma Y. So where
on the screen was that figure touched?
Now, what do I want to do?
So, I don't care where the user's finger is along the
X axis.
I only care where its on the Y axis.
So I don't care if the user goes up, down over here
or goes up, down over here.
He or she is is only going to be able
to move the paddle along some fixed axis.
So which value?
Dot X or dot Y is of interest to me here?
The location dot Y. So, if I want to center the paddle,
notice what I'm doing here,
turns out that center is a property associated
with the PaddleView or more generally,
any UI view has a center.
And I need to assign it in X comma Y coordinate.
I'm actually not going to bother.
I'm actually going to change its Y location.
But I'm not going to change its X location.
Because I don't want the paddle to start moving along the X axis
in this landscape mode.
I only want to update the Y axis.
What I need to assign its center in X comma Y coordinate.
So I have to actually give it a point,
a CG point make gives me that [inaudible].
Gives me an XY pair.
So, in the end, we get this very simple, kind of pointless game,
where the thing follows my mouse or my finger perfectly no matter
where on the screen my mouse is without actually responding
to the lateral movements.
Yes?
[ Background Discussion ]
Absolutely.
We could constrain the touch to only work, for instance,
if actually touching the white box.
By actually looking at the X coordinate and the Y coordinate
and saying, are you within some sort of bounds,
if so, move, if not, ignore.
Absolutely.
And we can kind of change the functionality
of this thing altogether if I instead change this line here
from the same X that it currently is
to Location.x. What's going to happen
if I now run this version?
Should follow my finger, or in this case, the mouse pointer.
If we go to the simulator here.
Put this up and this is kind of a stupider game now.
Well, actually, you might have an advantage now,
if playing pong.
So, all right.
So what remains to be implemented?
You saw pong a moment ago.
And you might've played pong years ago.
So, we've got the beginnings of it.
We've got the users half of the game.
What more do we need to do?
Yes? Yes, so we need to implement some kind
of little white ball that's going to bounce back and forth.
In fact, the bouncing sounds kind of interesting.
Because if it hits the top or the bottom,
we need to do some kind of reflection, like on a pool table
or like from geometry.
So we have to think about that.
What else has to be implemented?
So the tally, we have a big score at the top.
So maybe that's a UI label.
We can kind of cut some corners
and not do everything in graphics.
We can actually just use a font and actually update two labels
for the left guy's score and the right guy's score.
It's collision detection of what?
[ Background Discussion ]
Yes, exactly.
In addition to the top walls from which we want some bouncing
to happen, the end walls mean appoint has to be scored.
So we have to somehow detect if you've gone too far left
or right with the ball.
And we have got to detect if if you've hit the left
or the right paddle and that ball have made contact.
So there's a lot more to think about
but these are all probably buildings blocks we can start
to piece together.
So let me go ahead and open a final form of this and see
if we can pluck off piece by piece.
And see what the origins of each trick are.
So here is, I propose, a working solution.
And even I kind of cut a corner here.
Based on the files you see here,
what corners have I cut thus far?
Really just in the interest simplifying things we've already
looked at.
Yes? Yes, exactly.
I have a pong view, which we'll see,
kind of manages the whole game.
But I don't have a PaddleView anymore
or I don't have a ball view because I realized along the way
that you know, it'd actually be a lot easier to make a paddle
in Photoshop and a ball in Photoshop
and just import [inaudible].
And so, I seem to have done exactly that.
Paddle dot ping and ball dot ping are are just going
to be graphics.
But that's enough.
I just can't put out pings on the screen.
What object what class do I have to wrap around these images
as we saw with Rob before?
So a UI image view.
So we're just using a different UI image view rather
than making absolutely everything from scratch.
So, we'll start as always in the app delegates.
Nothing going on there.
AppDelegate.m, nothing new going on there other than actually,
this is one good thing to highlight.
We've used the AppDelegate for terribly little other
than the built in functionality.
But what do I seem to be doing
with this application will resign active?
A bit out of context now, but take a guess.
What does this mean and what am I doing
in response to it, do you think.
[ Background Noise ]
How about the first question first.
When does this method,
applicationWillResignActive likely get invoked?
When I what?
Close. Just the . Will resign.
Go ahead? So, it's not actually orientation, it's instead
when the app is background.
So if I get a call and I take it or if I push the home but done
and I resign active state.
Remember when we make key made the key an active
window earlier?
This is the same idea.
The opposite of that.
So, what am I doing?
I'm apparently passing a message called kickOff
to self.viewController.
And I only know this intelligently in hindsight,
the first time I sat down to implement something like this,
anytime I did get a call or anytime any background
to the application then came back
to the application, I immediately lost.
Because I had no recollection of where the ball was.
My brain wasn't quick enough
to actually move the I tell my finger
to move the paddle to catch the ball.
So then I've realized wait a minute.
If the user has to effectively pause the game to take a call
or respond to an SMS, background and whatever,
it'd be a nice courtesy to pause the game.
So kickOff does effectively that.
It just moves the ball back to the kickOff location.
The idea being I figured, let's just start
from the let's not reset the score.
Let's just reset the ball's location to the middle.
Like you might have in a soccer or football game.
All right.
So that's the only difference there.
PongView.h doesn't seem to have much going on here.
PongView.m looks like this.
Up too much, but a little of this low level stuff.
And I thought I'd draw something different.
Let me open up the game again.
And in the simulator there was one other design element
on the screen.
Does anybody remember what?
[Inaudible] yes, the dash line in the middle.
So this is surprisingly non trivial to do.
And I didn't want to resort to Photoshop for everything.
But I thought that would kind of look
like a nice line down the middle.
And we can draw this using core graphics on top of my canvas.
So in this case, I first need to get something called a context.
And the context you can kind of think of as like the canvas.
The current context for your graphics.
And now we have some sort of weird use of C.
But in the end it's fairly straight forward.
I'm first declaring a variable called dashes.
That's of what data type?
It's sub type CGFloat,
but specifically it's an array of CG floats.
Whatever that is.
Core graphics float.
So it's some representation of floating point values
for this particular library.
One comma one is essentially as we're going to see,
it's going to mean, draw a little bit
of white then have blank space.
White blank.
And that's how we get this sort of zipper affect of the screen.
All right so, CGContextSetLineDash.
So this function is essentially saying, what's your canvas?
Dashes is what pattern do you want to use?
And two just means how big was that array?
Next line here, CG set stroke color
with color what's your canvas?
What color do you want me to draw in?
So in this case, this is a bit of a commingling of C
and objective C. UIColor's a class.
WhiteColor is a convenience method or class method inside
of that class that returns to you some
of objective C representation of the color white.
.CG color converts that NS UIColor object
to a C style struct for the core graphics library.
Down here we set the line width
to be fairly arbitrarily five points wide.
We move to the point, 240 comma 0.
So we're essentially going to the middle of the screen.
If we assume 480 pixel, 480 points total.
AddLineToPoint, this is saying,
go from where you are all the way up to the top.
So sort of draw that dash line.
And then lastly, fill in the dots,
so paint along the trail you just left.
So if you remember like a language like a logo years ago.
The little turtle turning up, down, left, right.
And drawing things or leaving a trail?
It's the same kind of idea that where you move a cursor around
and you tell it when to put the marker down and draw.
When to let go and so forth.
We've essentially drawn a dash line in that way.
And now the whole point, was again, to over lay on top
of our view, this pong view.
So here we have ViewController.h. We're almost
into the brains of the game.
ViewController.h apparently declares one method
called kickOff.
Why did I put it in my .h file?
I feel like I'm regressing to our previous techniques.
Yes?
[ Background Discussion ]
Exactly. In my ViewController, rather in my AppDelegate.h,
recall that I called AppDelegate.m recall
that I called the kickOff method in this line here.
And that's why I imported the ViewController.h. And that's why
in ViewController.h,
I'm actually declaring this method publicly, so to speak,
in the .h file and not in some nameless category
in the .m file.
All right?
So, the nib file looks like this.
It's a little different this time.
And then I've seem to have laid out in advance,
a few different widgets, so to speak.
What appears to be on the screen here?
So some text.
So I con conjecture this is a UI label.
That's another UI label
and I just put some default text there even though the human
never sees it.
What else is on this screen?
Yes? Yes, so the image views.
So let's take a look.
If I first expand to the hierarchy here,
I can see what I've laid down on this canvas.
And indeed, there's three image views
or UI image views, the class name.
And to labels.
And if I actually click on these things,
with we can see how they're configured.
Let me click on the ball in the middle there.
It's ten pixels by ten pixels according
to what I made in Photoshop.
And it's in data UI image view whose image source has been
specified to be that ping in question.
Just like we did with Rob [inaudible] earlier.
Same deal for the others.
And score left and score right,
if we go to the identity inspector, is indeed a UI label.
So in this case, what I literally did
in advance was I dragged and dropped three UI image views
from the pallet of options down there.
And I configure them, just like I did with Rob earlier
to be ball.ping or paddle.ping.
So as to lay that out.
And then the scores I just manually typed.
Previously, they just said label.
And they could still say label.
I just thought it was a little more instructive
to give them left and right names, that's all.
All right.
So now if we go to ViewController.m,
here is where all the interesting stuff must
be happening.
So first, I decided just to make it easy to tinker with my game,
to declare a velocity, constant at the top of the file.
Initialized to 10.0 in a floating point value.
So this is like the speed, ten pounds per second.
And or some unit of time.
And then I have inside
of my nameless category, a CG point velocity.
So, somewhere in this class, I need to keep track
of what is my current velocity.
Because a velocity recall was essentially a vector telling me
how fast to go.
Up to straight up or to the right or the opposite thereof.
So it's some kind of speed, a change in rate, DYDX.
So I need to store my current one so I know at every second
of the game how fast should the ball be moving.
Now I have a whole bunch of private properties here.
But most of it is expected.
Then I've got IB outlets for all three
of the UI image views that we saw earlier.
And I've got two IB outlets for the UI labels
that we dragged and dropped.
So that leaves a few here, an NSU integer.
What might that mean?
Yes, so it's an unsigned integer, why?
I figured the score never needs to go negative.
So just to be proper, I'm going to specify that it's an unsigned
that is non 0 integer.
I could have just done little U, unsigned int.
But, just to be consistent with iOS practices,
I gave it the NSU integer, which is just the it's not a class,
it's just a type depth, it's a synonym for unsigned int.
All right, I've got one for the left and one for the right.
And [inaudible] for pause.
I needed some variable just to keep track of whether
or not the game is paused and when does it seem to pause based
on our tinkering earlier.
What's that?
When it's in the background and also in the beginning,
when the ball is just sitting there
in the middle before I actually start interacting with the app
or conversely every time there's a score made,
then the ball goes back to the center and I have to touch it
for the game so resume.
All right, so now, in the ViewController,
some of this is a lot of this is now just logic.
So, after initializing the object with the nib name,
I'm initializing the score left and right to 0.
I'm first declaring a velocity.
So a velocity has to do with motion.
And you can represent it with a point.
If a point is just X comma Y, you can just treat the X
as delta X and the Y as delta Y. Change in X, change in Y.
So I just used them now familiar CG point make velocity
comma velocity.
And this just means if it's 10.0,
what did we say it was earlier, the constant.
10.0 this just means that for every unit of time,
move ten points this way, ten points that way,
effectively going on a straight diagonal.
All right, so what happens next in this initializer?
This is how the game actually has motion.
So we declared what's called an NS timer.
We schedule it with a time interval of .05.
So every five hundredth of a second I want something
to happen and I just decided on that by trial and error
to see what would feel right.
Targeting myself with a selector of play.
So apparently, I want what method
to get called every .05 seconds?
The play method, all right?
And beyond that and it repeats, in that, if you recall
from Java Script, they're set interval
and they're set time out.
This is like set interval, given that I'm passing
in repeat, a value of yes.
So now, what happens next?
Nothing seems to happen thereby default, let me scroll down,
there's a play method.
A lot of math there, touchesMoved.
So touchesBegan.
So it looks like what I'm doing here is when there's a touch
on the screen, I am changing the value of paused to no.
So this is my main way of kick starting the game.
As soon as touches begin on the screen, doesn't matter
where the human touches, that means kick the ball.
Let's start the game of pong playing.
And I change that [inaudible] field.
So presumably, my play method is going to check that value.
So let's go into play here.
And indeed, if the game is paused, just return immediately.
Don't play anything.
Don't move any mouse movements or cursor movements or ball
or paddle movements otherwise move the ball.
So this is very similar behavior to before.
Even though this is being called on a timer not in response
to user action, what do I want to do every unit of time?
I want to move the ball how?
Using its velocity.
So if its velocity is ten comma ten, every time the clock fires,
I want to move it over ten and up ten,
if that's its current velocity.
And that's what I'm doing.
I'm making a new point.
Taking the ball's current X location,
adding the velocity's X values.
Then comma, the ball's current Y location.
And adding the velocity's Y value.
But now I have to somehow detect when the ball's in the goals
as was proposed earlier.
So, what is this line of code saying?
If self.ball.center.x less than 5,
what's the implication of that logic play?
[ Background Discussion ]
Exactly. So recall that 0 comma 0 is the top left hand corner.
So if the ball goes within five pixels of 0,
it's really all the way over to the left at which point,
I'm just going to say that's the goal.
It went over the boundary.
So who should get the score?
The guy on the right.
So score right should be plus plus.
Because he's the one who would have kicked it into that end.
And then I called self kickOff.
Well, what does kickOff do?
Let's come back to this function this method in just a moment.
KickOff does a few things.
It pauses the game, apparently.
It then updates the scores based on what's in the NSU integer.
So the unsign integers are numbers.
But I want to turn them into strings so that I can paint them
on the screen in terms of those labels.
So that's using some building blocks from a few weeks ago.
Now I want to center the ball.
And I'm going to go ahead and center this
at that particular location here.
And then I'm going to go ahead and align the paddles,
which is just a bit of trial and error.
Figuring out exactly what made sense on the screen.
And now if I scroll back to play, what happens otherwise
if there's no goal on the left or on the right?
Well, bouncing is kind of an interesting thing.
So what is this, if condition, handling?
The highlighted lines are doing what and how?
Yes?
[ Background Discussion ]
Okay, good.
So as the comment says, this has to do
with bouncing off the top and bottom, but how?
Well, if the Y coordinate of the ball center is less than five,
that means it's really close to the top.
And if its velocity at that point is some value,
how do you make it stop going upward?
Well, just change the velocity to the negative.
So if we effectively want to make right angles
when we hit the side of the wall, it actually suffices.
If again, you think of the motion as X component
and a Y component, if the ball is going up this way,
you don't want to change the X motion.
Like, you don't want it to go this way,
because that would be weird if the ball hit here
and then went this way.
You want the ball to go this way and keep going to the right,
but you want it to start coming down.
So all you have to do is flip the Y from positive to negative
or conversely negative to positive.
And that's exactly what we're doing inside of this condition.
If we get within five pixels of the top of that screen, go ahead
and flip the Y's velocity as with
that negation there in that line of code.
And the [inaudible] is just handling the bottom
of the wall as well.
And the fact that I'm using a negative sign here means
that it doesn't matter if the ball is going up
and now would have come down, or if it's going down,
now it's going to go up.
The left paddle is a little more interesting.
And how are we apparently detecting intersection?
Well it turns out in the core graphics library,
there's a helper function called CGRectIntersectsRect.
And you can pass in two rectangles.
And it will return true
if they're overlapping, which is perfect.
And this is why I didn't quite make the ball a circle
and decided it'd be easier
to just make it a ten by ten square.
So this way no matter where it touches,
it's sort of geometrically reasonable to assume
that it's going to bounce.
And so in this case, if the frame intersects the frame
of the ball intersects the frame of the paddle then, go ahead
and inverse the velocity, from negative to positive or positive
to negative, depending on which paddle you have just hit.
If you're on the left or you're on the right.
Yes?
[ Background Discussion ]
If you increase the velocity of the ball,
would you get a problem?
Define problem.
[ Background Discussion ]
Oh, good question.
Yes. So, potentially, I have made certain assumptions
about the thickness of the ball, the velocity
at which the ball is moving
and how frequently I'm firing the clock timer.
I could absolutely come up with values whereby the ball could be
here at one firing of the clock.
And then here at one firing in the clock.
And the paddle could have been here in the middle.
So that would just be a mathematical mistake on my part.
And something that could I'd run the risk
of if I had variable velocities.
But all I'm doing with my velocity here is just inverting
it, positive or negative.
Good question.
Other questions you have?
All right, so, here is my artificial intelligence,
if you recall want to have basic AI in your game.
Really, all I have to do is tell the paddle
to move toward the ball along that Y axis.
And as long as he can move just as quickly as the ball,
he will never make a mistake.
So what am I doing?
So, if the velocity at which I'm moving is negative,
what does that actually mean?
If the ball is moving left so that means that it's coming
at the computer's paddle.
My paddle was on the right for this version.
Computer's on the left.
So if the ball is moving this way, that's the indicator,
according to this code the computer AI should start
doing something.
So if the ball's center Y component is lower
than the paddle's Y component,
the paddle should per the next line
of code move its center toward the ball.
Conversely, if the ball center is higher than the paddle,
the paddle should move up toward the ball.
And so, no matter what it seems,
this paddle will always keep pace with the ball
and really only I, the human, am ever at risk of losing.
So let's see if this is indeed the case.
If I run this version of the game.
We now have two paddles on the right.
If I click, that's when the kickOff starts.
And notice, he only moves when the ball is coming back at him,
because of that check.
Though we could add some randomness if we really wanted
to give the human a fighting chance,
we could have the paddle keep moving somewhat randomly.
We could change its speed.
But for the most part, we have a pretty boring game.
But we can make it more interesting if we go back here.
And what can make it more interesting?
How about we change this to 30 points per unit of time.
Now, if we rerun the program,
we'll get a game that's a little harder.
And come on now, if I click damn it.
Damn it [chuckles].
[ Chuckles ]
There we go.
Thank you [chuckles].
Okay. So it's really hard now.
I mean, if you can imagine making this into even more
of a game, maybe a utility app where it flips over.
You can change the size of the paddle,
kind of like a game arachnoid years ago,
where things get harder
or easier depending on the settings.
So there's a number of things you can do with this.
But at the end of the day, we've really didn't write all
that much code, right?
We asked iOS to inform us
when is the movement happening with the touches?
So we could respond to that.
Then we drew some things in advance.
But we've seen that we could totally skip the Photoshop step
and just draw these paddles as their own classes
and instantiate them
and do something almost identical with the ball.
Just making it a little smaller.
And at the end of the day, the only thing
that I'm doing here is I'm borrowing some code
from my paddle example.
Anytime the touches move, method is called.
And that means something has happened on the glass
where the human's touched.
I'm going to ask, give me one of those touches.
Figure out what its X comma Y is.
And move the right hand paddle to that side of the screen.
So, really, the human side of things boils
down to just those three lines of codes.
We have yet another few pieces of buildings blocks there.
So any questions on our first two dimensional game?
[ Background Discussion ]
Good question.
Am I doing anything to prevent the paddle
from pushing off the screen?
Yes, I am in the sense that my code is only ever altering the Y
axis of the paddle.
I'm only allowing it to move up and down.
So notice here, recall this line of code
from our previous example.
The paddle on the right, his center,
is only ever being updated according to the Y axis.
So notice, this value here, the X value,
this is literally the paddle's current X location.
Because it's self.paddleRight.center.x. So,
what is your current X location?
And the fact that I've pasted that as the first argument
to CGPointMake, means whatever your X location is now,
it's going to stay that way,
because that's the new point that I'm making.
But location.y is coming from what?
From the human touches based on these two previous lines.
So in short, this third and final line of code
in here is just ensuring
that the paddle's center will absolutely be able
to go up and down.
But it will never respond to left, right movements.
But with we can decouple those.
If I go back, just like I did last time, and say, "Go ahead
and let the user have location.x," and now run this.
Now this game's I can't do 30 points per second, ten?
Now this game gets a little more interesting in that I have a bit
of advantage where I can just kind
of chase this oh damn it [chuckles] over there.
So that has to do with the refresh rate, so to speak.
So now the math a little off
in that I can't assume a certain access.
But now I have decoupled it from that axis.
Oh, it is.
I'm just stopping.
My mouse can't quite pull it all the up there.
But yes, it's going off the screen somewhat.
And with he can detect that too,
because we know the height of the thing.
And we could just ensure
that you couldn't go any higher than the glass.
In this case, but if you've ever been bored
like what do I usually do on my phone?
Sometimes when you're really bored in iOS,
you can start using your thumbs and like start pulling
down on Safari to see how far [chuckles].
So other people have done this yes?
Okay. So someone has checked for that in Safari,
we have not checked for that here.
So, in theory, you could get it to go off the screen
and probably get it such that you can't, maybe,
can't get it back depending
on where it's detecting the fingerprints.
I'm glad that's normal behavior [chuckles].
All right.
Any questions then?
All right, so what the lies ahead?
Well, evil hang man is still in front of us.
On Wednesday, we are going to take a direction
in a lab that's not specifically about the final project
because there is no one specification.
It's up to you guys to propose this.
We'll have the specification posted for it on Wednesday.
But it'll essentially boil down to come up with an amazing idea.
Propose it to your TF and await his confirmation or request
for modification to the idea.
And the request won't be, "We don't like your idea,"
we'll be more, "We don't think that's realistic in two weeks."
Or we think "That's too realistic in two weeks."
Just to give you a sense of calibration
so you can bite off something that you can indeed chew.
And what we'll do is try to calibrate you
so you have a threshold, a quality threshold,
that you'll definitely need.
And we'll also try to push you a little bit to have, say, a good,
better, best version of your application.
Or it'd be amazing if you get the best version.
But we'll be quite pleased if you get the good version
out the door in time for that app party.
So in lab this week, what Chris Gerber will do is introduce you
to some more advanced techniques in iOS
to further seed your minds with opportunities.
Even though the proposal will be due shortly thereafter.
Realize that you can change your mind.
If you realize, "Wow, I love the accelerometer.
I really want to do this instead."
Just make sure to have a two way conversation with your TF
to make sure it sounds like a reasonable change.
Why don't we officially an adjourn here for tonight
and we'll see you next on Wednesday.