WWDC2013 Session 611

Transcript

X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> In this session, my colleague
Mark Malone and I are going
to show you how you can take
your content to your next level
by adding your own
customization while maintaining
great performance.
So first, let me give
you a quick refresher
of what iBook Widget and
iAd are that are rich
in application running
on iOS device.
You can do a lot
interesting things.
Browse a gallery.
Play a game.
Amazing performance.
You may think this is
a native application.
However, if we look
under a cover,
there's this mini
website working
in HTML, CSS and JavaScript.
So there isn't any rocket
science involved here.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So if you're a web
developer, it's good news
because you're experience
and knowledge is going
to be really valuable here.
Even if you're not
a web developer,
don't worry because iAd
Producer make it super easy
for everybody.
So here is what we
will learn today.
First, we're going to look
at content customization
and then we'll you
look at testing
and debugging techniques.
Lastly, we're going to cover
performance optimization.
So content customization,
how are we going to do that?
Under a cover, iAd Producer
create your content using
web technology.
And we can use the same exact
technology to do customization.
First, I'm going to show you
how we can do some custom style
using CSS.
In iAd Producer, I have
this project in development.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This is image in
the center I would
like to apply some
custom style on.
First, normally, my
first approach is
to use the auto-inspector.
I can do a lot interesting
things there.
I can [inaudible],
apply a filter.
Behind the scene, like those
auto-inspector are applying
CSS property.
So you're already
writing custom CSS
if you are using this inspector.
It's just that iAd Producer is
doing it for you automatically.
But what if you--
what if you want
to use some CSS property not
backed by this inspector?
There are two ways
to go about it.
The first approach is
to import a CSS file.
In iAd Producer, you can
import CSS JavaScript file
like you could for
image and video.
And the CSS JavaScript
file will get bundled
with your content
automatically on export.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
In this particular example,
I imported a file
called custom.css.
Let's take a look.
Inside that file, there's
a custom style setting skew
transform and it's
targeting object
with custom-transform
as a class name.
If I go back to my
project, at this point,
the image is not getting
the skew transform
because it's not having--
it doesn't have to right
custom CSS name applied.
To fix that, we can go to
the property inspector.
And there's a CSS class field
and I can type in
custom-transform.
At this point, if I do
export or assimilation,
I will find that the
skew transform is applied
to the image in the center.
So that's one way to apply
custom CSS in iAd Producer.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now, we go and look
at another approach.
The second approach is
to use a Code Editor.
We can open the Code Editor
by clicking on the Code button
on the bottom toolbar.
Here is what the Code
Editor looks like.
You will see a list
of file on beside.
Global.css is a file that you
can add you custom CSS style
and make it available
to your content.
Global.js is the same idea
except uses the JavaScript file.
So previously, we applied a
class name to our image object
and we can use it right
here in Global.css.
And here's an example.
Here's an example of pocketing
an object by its class name.
We can also target the same
object by its unique ID.
Let me show you how that works.
So back to our project.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
iAd Producer automatically
generate a unique ID
for every single object
by combining the page name
and the object outlet
name with a dash.
Let's take a look
at this example.
In this project, we have
a page called Introduction
and the object outlet
name is "curiosity".
Therefore, the unique ID
for their image is going
to be Introduction-curiosity.
And here's an example how I
can reference it in Global.css.
Super simple.
So that was CSS customization.
We're going to shift focus
and talk about JavaScript.
So at this point, I have
a really beautiful page.
But at the same time,
it's not that interesting
because this is only
showing a static image.
I want it to be dynamic and
always look fresh to our user.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
To do that, I'm going to
write some JavaScript code
to point the latest satellite
image from NASA and display it
in a multi-cell object.
To start, I'm going to show
you how we can get that data
from NASA and-- on page load.
So in iAd Producer, we can
Object and Page by event
and we can add customization
by implementing JavaScript
callback for those events.
And we can see the event by
going to the Code menu item.
And for example, we're going
to look at the Page Event.
And there we can see a list
of event, the Page Flyer.
View Did Load is
particularly interesting
because it's the
event that got fired
when the page finished loading.
We going to choose that
and we'll see a list
of action base available for
the event, and we're going
to pick Execute JavaScript.
When we choose that option,
we will see the Code Editor.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And there we can add the code
to connect to the NASA server.
So how do we do the
server connection?
If you talk to a web developer,
he or she will probably
recommend something called
XMLHTTPRequest, it works.
But in iAd Producer,
we have something nicer
for you to work with.
It's called iAd.XHRLoader.
It's a really nice
and simple API,
and let me show you
how that works.
You can create an object
of iAd.XHRLoader by
passing in a URL.
Imagine the blue box you
see here is an object of it.
Every iAd.XHRLoader has
an interesting property
called delegate.
The delegate letter
iAd.XHRLoader know who notify
when the loading status change.
And it could be any
JavaScript object.
In this diagram, I'm
going to assign it
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to an object represented
by the green box here.
And I did-- with
this [inaudible],
I can ask the iAd.XHRLoader
to start loading and one
or two thing would happen.
If the loading is successful,
the iAd.XHRLoader is going
to fire a loaderDidComplete
notification
and the green object
will receive it
and do some interesting
manipulation
with the return data.
However, if their loading
turned out to be unsuccessful,
it will get different
notification called
loaderDidFail and the
green object will get
that notification
and it could choose
to do some error
handling from there.
So this gives you-- this
diagram gives you our view how
iAd.XHRLoader works and
here's how it looks in code.
It's supper simple.
It doesn't take that
many lines of code.
We are going to look at this
in detail in a demo shortly.
Now, let's look at-- let's
move on to the next task.
I'm going to show you how we
can use the data from the server
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and populate it in
a multi-cell object.
So back to iAd Producer.
I have replaced a single image
with a gallery, a
multi-cell object.
And this form, we
have a data from NASA.
I'm going to show
you how we can plot
that into this multi-cell
object we see on screen.
So imagine the gallery we
saw earlier represented
by this purple box
you see on screen.
Every multi-cell object
have an interesting property
called dataSource.
The concept of dataSource
is really similar
to delegate property
you saw earlier.
The dataSource property let
the multi-cell object know
where its data is coming from.
Imagine the dataSource
is represented
by the green box you see here.
In order for the green
object to supply data
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to the multi-cell object, you
need to implement two methods.
The first method is
numberOfCellsInContainer.
It lets the multi-cell object
know how many cell there's going
to be.
The second method is called
cellAtIndexInContainer.
It just returns the cell
object at a different index.
So this gives you an overview
how to load a dynamic content
in a multi-cell object.
And here's how it looks in code.
It's also super simple.
It doesn't take that
many lines of code.
To give you a concrete
idea how these all work,
I'm going to ask Mark
to give you a demo.
>> Great.
[ Applause ]
Thank you very much Chi Wai.
Great. So I've got here on
my canvas, we're building--
this particular example is
an iBook widget and I've got
on the canvas one of
these multi-cell items.
And you can see, if
you double-click on it,
I can look at each one
of the cells in here.
And the sort of the standard
behavior for laying this out is
to jump in here and maybe I've
got three event associated
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with Mars curiosity and I want
go and add a new one, well,
I can drop in a new cell here.
I can lay it out to
look like the other one
or maybe I can have a sort
of arbitrary content in there
and it's a really
nice easy way to go
and layout quite
a bit of content.
But if you go in
and you preview it,
you'll see that it will
preview it in a way that,
except for that cell,
actually looks really nice.
There's this nice fluid
motion back and forth
and it looks a lot like
a cover flow experience.
It's all tied up for
tap and ready for people
to attend, interact with it.
So if I close my preview
here and go back to my cells,
you'll see that I
can double-click in
and I can actually delete
cells as well, right?
So this is how you can go and
edit this if you want to go
and add more cells
when they're static.
Now, this is a gallery view
and if I select the Inspector,
you'll see that I got one
of the cells selected.
But if I just click out, you'll
see that it's a gallery view.
It's got a name here.
And it's a good example of
one of our multi-cell objects
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that has some great properties.
But we actually have quite a
few of those multi-cell objects.
We've got this wizzy
carousel that will spin
and it has multi-cells that
you can go and pop content in,
and a true cover flow view.
This is an example of a gallery
here that I've got on the canvas
and then a series of
other kinds of examples,
and they're all going to have a
different visual representation.
But from a sort of dynamic
and interactive capability,
they're going to have
a great experience
and that's what you're
going to want.
So, this is a rather
static implementation
and I think the whole point
to this particular example is
to take this cover flow or
this flow view that's up here
and convert it to something
that's much more dynamic.
We're going to call
to the server.
We're going to get these
milestones that you see in here,
bring them back, and
populate this thing based
on just calls to web server.
So the reality is I don't
need any of these cells.
And if there's any content in
here, I certainly don't need any
of the content associated
with it as well.
And it's going to bring it down
to basically a prototype cell,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
one cell that's going
to represent sort
of the cookie cutter that
I'm going to use for each one
of the calls that I make to
the network or for each one
of the records that I get
back from the network.
And so maybe I'll go and
just make it real clear
that this is generic
information I can put in.
This is a date, placeholder
and title that goes here.
Get a little more room here
and the description goes here.
You sort of get the picture.
This is just sort of a
cookie cutter that I'm going
to use repeatedly after
I call to the server.
So let's get into
some of the code.
I want to make a call to
my web service and I want
to pull back all of
those events on the fly.
Maybe there's a new step in
the Mars curiosity landing
and I want to have that
show up within my iBook.
Well I've got some
really cool interaction
with the social media and I
want to pull that content back
into my iAd on the fly as well.
Well it's these technologies
that will make this work.
So, what am I going to do?
I'm going to click the
Code button, bring it up.
Hopefully, it's large
enough so that you can see.
I have nothing selected on the
page when press the Code button.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And so, what it did was
it opened the Code Viewer
in the context of the page.
If I had a button selected,
it would open the Text Editor
and the context of the
button and you sort
of get the way that it works.
And so, what have
you got in here?
Well you got the name of
the page here on the left.
It will be unique JS file
for each one of those objects
that I'm going to go
and add some code to it.
Drop down for all of
the events associated
with this particular object so
I can hook into the viewDidLoad,
will appear after it's
actually appeared,
or I can have code fire
as the page is going
away, going to hide.
So, this is the little
function that I'm going to go
and override when this
function is called.
I'm going to have my code that
calls back to the server kickoff
and this is what
it's going to call.
It's going to call
a local web service
that I've got running here.
I've got a little JSON feed.
It's a parent is a timeline and
it's got a series of milestones
for each one of the Mars
curiosity landing milestones.
And as, you know, something
new happens with the curiosity,
I'll go and add a
new record to here.
And whenever this particular
add or this widget is opened,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
it's going to call
to this feed and pull
in the appropriate
content there.
So that's what it looks like.
And the way that I'll go and
implement this is using one
of those great classes that
we've got within iAd Producer.
And so, I'll just drag it
in here, cheat a little bit.
Drop the code in.
And just to explain what I'm
doing here is I'm going to go
and get a reference to that
gallery view that's sitting
on the page.
You saw that it had a name
of Timeline Gallery View
and I access it through this
outlets which is an array
of all the items sitting
on a page, and I'm going
to store that in a variable.
And then the next class that's
really cool here is this iAd
Archiver class.
What I'm going to do
is I'm going to go
into that gallery view
that's sitting on the page,
take that one cell that I
created as my prototype cell
and basically create
a serialized version
of that storage.
Sort of freeze dry it and save
in this property sitting
here on this page.
Pretty straightforward behavior.
The next step is I'm going
to go and call a web or set a
of web service variable
to the path
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to that JSON file that you saw.
I'm going to hold the results
of the call to the server
in this variable called
Milestones and I'm going
to initialize it so I
don't get in trouble later.
And then here is the
magical XHRLoader class
that I'm going to call.
And again, this just is a
wrapper for XMLHTTPRequest
but it's super simple to go and
implement and you don't have
to look at ready states
and the other properties
that typically you're looking
at, at that particular level.
So here I'm instantiating
my object.
And if there's any confusion
about, well, what is this class,
you'll notice that I've got
documentation that's built right
in and I can show
the documentation
or I can find the text
that I had selected.
And if I want to get a
little bit more information
on this class, I could just
type it in and you'll see
that it will filter the list--
oops-- XHRLoader, there it is,
and get the various details.
But I pretty much
know what I'm doing
for this particular example so
I don't need to bring this up.
But it's really nice to have
the DOCs right there for you.
All right, so I'm instantiating
one of these objects.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I'm setting its delegate
property this page,
meaning this particular page
is going to want to listen
for all the callbacks associated
with the success or failure
of calling my particular
website.
And then I'm going to tell that
bad boy, that loader object
to go and fetch the
content, load the content
that you're pointing to
here, and that's what
that load call does there.
So as I said, when I call
Load, it's going to call one
of two methods, we
saw them in the slide.
Let me just go ahead
and drag them
in from my little
cheater over here.
Drop it in.
It's loaderDidFail.
We pass in the loader,
so it will be a reference
to this instance
that I created here.
There'll be an error
code as well.
And here I'm just
throwing up a silly alert.
You know, you need
to do something a little
bit more important here,
especially if you know that
there's no network connection,
you might want to
load some resources
from the local file itself.
Maybe put placeholder images
there and some placeholder text
in case there isn't an
internet connection.
And this is the
loaderDidComplete call.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And this is, if I successfully
called back to my server,
pull back all that JSON text,
I'll be passed back that loader
and I can inspect it,
pull the content out of it
and do some interesting
things with it.
So rather than having this alert
pop up, I'm going to go and drop
in some more code in here.
Boom. And what does this do?
Well, here I am getting
a reference
to that gallery view that's
sitting on the page again
because I'm going to want to
go and poke some data into it.
Saving it as a local
variable called Gallery View
and then I'm going to go and set
that dataSource delegate
property that Chi Wai mentioned.
And by setting that
property to this,
I'm saying this page
is interested
in all the callbacks associated
with how this gallery view
is going to get populated.
All right, the next step is to
grab this loader that came in.
Ask it for its context, what's
going to be that raw text
that you saw in the JSON feed.
I'm going to convert it to a
JSON object by calling Parse.
And then I'm going to pull out
those milestones that you saw
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in there which is going to go
and basically set this local
property array to have all
of those values in it.
So now I've got an
array full of objects
for each one of my cells.
And the last step in the
entire process here is to go
and tell the gallery
view that's sitting
on the page to reload its data.
And when it does that,
it's going to call its
dataSource delegate and say,
"OK, what you got for me?"
And the way it does it, as you
saw on the slides, are these--
boom-- these two particular
calls, numberOfCellsInContainer
and cellAtIndexInContainer.
This first one says, "OK,
I'm this multi-cell view.
I'm supposed to show a
whole bunch of content.
Well how many of this little
view should I display?"
And so, this should return a
number and I'm going to try
to type it with one hand here
which is basically I'm going
to go to my milestones variable.
It's an array, so all I
care about really here
for this is the length.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Perfect. So it's going
to say, "OK, yeah.
Gallery view, I got this number
of milestones in my JSON feed
that came back, so
this is how many cells
that you need to
go and fill out."
This particular function here
is cellAtIndexInContainer
and it passes in that gallery
view there and it also passes
in the index, which one of the
cells doesn't need to display
at the particular time,
and what I'm supposed
to do is create a view,
instantiate a view
and just return it a result
of this particular function.
And the multi-cell container
will go and drop it into one
of those cells as a subview.
So it's super easy
to go and implement.
So rather than return Null,
let's return something
interesting here
and here is the actual
code for that.
Drop it in, there we go.
All right, so let me
go through this again.
I'm creating a new view and
I'm using that archived one,
that freeze dried one
that I saved early
when these ad first launched.
And I just say restore
from Archive
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and what it does is it
instantiates one of those views
with the image placeholder,
the title and the date
and the description
field at the bottom.
It gives me a new
instance of that.
I'm going to go and grab
the particular instance
or the particular milestone that
was returned from my JSON call
and that's passed in
as the index here.
I've got this array.
I'm going to pull out
the one that I care about
and put it in this variable.
And then the rest of
this content is going
to create an image based on the
URL that's being passed in for
that particular image and
then set the various date,
title and description properties
on that particular
freeze dried version.
And then the last step
is, OK, return that back
to the multi-cell container
so it can plunk it in
and drop it in the right spot.
So that's all the
code that I need.
Just move that over.
Go back to my view,
nothing at my sleeve,
no assets in here, no.
If I hit Preview here, it made
the call to the local server
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and there are all the
items sitting in it
and even some additional ones,
just so you know
I wasn't cheating.
So all of this content was
being pulled on the fly.
And like I said, you could
go and add another item
on your server the next
time this is launched.
It would go and pull down
the appropriate content.
So that's a bit of an overview
of pulling content on the fly.
I think one other thing,
just to mention really quick,
is these multi-cell
views, if you look at them,
you'll see that you can
add more and more and more.
And if you're worried
about memory consumption
when you're building this
out, just keep in mind
that we take care of doing a lot
of efficient memory
management with these.
I could, say, insert cell,
insert cell and create 50
of these, but from a DOM
perspective, what's in memory,
we make sure to set
display none on those items
that aren't visible
at any given time.
So that's something that we take
care of so that you don't get
in trouble in case you
pull down 300 cells
and want to go and populate.
We're pretty good with
the memory management
and that's actually a
really good best practice
for you folks as well.
So that's the demo and I'll
pass it back to Chi Wai
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to take it to the next step.
>> So that was JavaScript
customization.
We're going to shift
focus and talk about HTML.
So if you look into--
in iAd Producer,
if you look into
your Object Library,
there's an awesome object called
HTML Under Dynamic Content.
We can add that to canvas.
And double-clicking
on the object,
it will give us the Code Editor.
And there we can
add our custom HTML.
The HTML object is
super flexible.
We can literally put any
kind of HTML code inside.
One great use case
is format of text.
With the HTML object,
we can do all kind
of interesting things with text.
We can set the font,
color, create hyperlinks.
The sky is really
the limit here.
Another great use case of
the HMTL object is MathML.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Back to your Code Editor,
I can define my mathematical
equation in MathML.
If I go back to canvas and
look at my HTML object,
now it becomes a
mathematical equation.
It's super beautiful and
also really straightforward.
So now if we go back
to our project
that we've been working on,
at this point we have
a beautiful gallery.
It's dynamic.
Always look fresh to our user.
But we're going to take
it to the next level.
We're going to add a video.
NASA have an interesting
site, like you have all kind
of video content in it.
However, it doesn't provide
direct link to the video file
so we cannot really use a
video player object built in,
in iAd Producer.
Fortunately, like a lot
of video sharing site,
it does provide an
embeddable HTML object.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And we can use it for our--
I mean we can use
it in iAd Producer
and let me show you how.
And now if we go
back to our canvas,
we can add our HTML object.
We can go to Code
Editor and paste
in the HTML snippet provided by
NASA and we save and close that,
we get our beautiful
video from NASA.
Super simple.
So that was HTML.
And I'll show you
a number of ways
to do customization
using web technologies.
I'm going to change subject
and talk about performance.
So performance and user
experience go hand in hand.
You cannot possibly provide
a great user experience
without having great
performance.
To help you accomplish the
best possible performance
on your content, I'm going
to talk about some testing
and debugging tools and then
I'm going to give some tips
and tricks for optimization.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
First, let's look at an iAd
project I have been doing
in the weekend.
It's a particle assimilation
model.
I figured out the
physics and math
and I think it's ready to go.
Here's the assimilation
I have on a Mac.
The particle is doing
exactly what I wanted to
and also the frame
rate is pretty good.
It's 50, 60 frame per second.
But if I run it on
my iOS device,
though I'm getting
their correct behavior
but I'm not getting
good frame rate.
I'm only seeing 20
frame per second.
So obviously, I'm not-- I mean
I'm not ready to ship this yet.
To help you identify issue--
performance issue
like this on device,
there are two tools you can
use for testing and debugging.
The first one is Remote
Web Inspector from Safari.
The second one is the Instrument
app that come with Xcode.
First, let's talk about
the Web Inspector.
The Web Inspector is a debugging
tool that comes with Safari.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
In iAd Producer, you can
attach a Web Inspector along
with your content on export.
And let me show you
how that works.
First, you want to make sure
you have Web Inspector enabled
on your iOS simulator
and device.
To do that, simply
go to Settings.
And if you go to Safari,
there's an Advanced option
and you can turn on
Web Inspector there.
And after that, we can go
back to the iAd Producer.
There's a Preview
menu item and we want
to make sure show Web Inspector
when Previewing is enabled.
So what that does is that next
time when you do a preview
where there is an iOS
device or iOS simulator,
the Web Inspector will show
up along with the content.
And let me give you an example.
So I do a preview and
will see my content
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in the background a Web
Inspector out front.
With the Web Inspector,
we can do powerful
performance analysis.
One thing we could do is
to identify CPU hotspot.
To get started, we need to
go a tab called Instrument
on the Web Inspector.
And we can start the
JavaScript Profiler
and we can run some
interesting report.
We can do a-- we can
run a report like this.
We can see the number
of call per function.
It's really easy to identify CPU
hotspot by singling out function
with a normal amount of calls.
Another thing we can do
with the Web Inspector is
to monitor network traffic.
On the same view, we can capture
a live network report like this.
If we take a closer look,
for every single file,
we can see the file size,
latency and duration.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So it's really easy for us
to identify network
inefficiency or bottleneck.
For memory related issue, we're
going to use a different tool.
Instrument is the
application we want to use
to identify memory
issue on device.
To set it up, first we
need to download Xcode.
Xcode is free on
the Mac App Store
and Instrument will
come along with it.
To give Instrument
the permission
to profile your iOS
device, first we need
to do some setup on Xcode.
So we want to launch Xcode and
go to the Window menu item.
In there, we want choose
the Organizer option.
Here's the Organizer window.
If your iOS device is
connected to your computer,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
you will see on the side bar.
To give Instrument
the permission,
you want to choose the device
and then click Use
for Development.
At this point, you're all set.
You can quit Xcode
and launch Instrument.
And this is a screen you will
see when you launch Instrument.
And you want to choose
Activity Monitor for iOS.
And you can get a memory
usage report like this.
Let's take a closer look.
With this kind of information,
you can see how much memory
your content is consuming
at a given point of time and
you can also see a breakdown
of the memory footprint.
Super powerful.
To show you Instrument and
Web Inspector in action,
I'm going to ask Mark to come
back and give you another demo.
>> All right, so here
is the actual project
that you saw on the slides.
And just to let you
know that it's real,
I'll hit the Preview button and
you can see it's running here
on the Mac and it looks great.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And that's, as you would
expect, it's running on a Mac.
The reality is we know that
if we write applications
or if we write websites that
have all sorts of complications
with them there-- within them,
they might perform differently
on the-- some of
the mobile devices.
I mean it doesn't have the
same fat pipe necessarily,
the same chipset.
And so, the reality is it's all
about testing on the device.
And we've got some great tools
to go and test on the device.
Now if you download and
install the Xcode toolset,
you'll get the iOS simulator.
And it does a pretty close
job of going and simulating
that have something
would run on the device.
You can choose Preview
and Simulator
and export the widget
rule, export the ad,
we'll launch the
appropriate tester application
on the platform and
you can bring it up.
Let me shrink it down a little
bit so you can actually see it.
And there it is running
simulated on the device.
Still pretty good of course
because it's not running
on the actual chipset.
It's not using the
same networking,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
those types of things.
But it's certainly
something that's capable
and gives you a really good feel
for, you know, how far you are,
how close you are to
doing the real project
or completing your project.
So, I'm just going to go and
close that, come back up here.
Another option is actually you
can go and Preview in Safari.
This application
generates great web content.
So, the reality is a lot of
this content will actually run
in Safari as well.
And so, a lot of folks will
just choose Preview in Safari
for just doing that quick look
of how their ad experience
or how their widget
experience is coming along.
And then the final one of course
is the one that you always want
to use, certainly
before you ship.
But also as you're working
in your design efforts,
you want to make sure
that you're building
something that's really going
to perform well on the device.
And of course, we've got built
in preview on device there
as well and that
will not be there
if you don't have
a device connected.
So if you launch iAd Producer
and you want to go demo
on device, if it's not actually
tethered, then you're not going
to see this particular menu.
But once you tether with
an iPad or an iPhone,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
this will become enabled
and it'll do the
right thing for you.
So previewing on a device is
definitely what you want to do
and we're all about trying to
figure out, "OK, what's going
on with this particular
examples?"
so I'm going to check Show
Web Inspector when Previewing.
And of course, the Web Inspector
will show in all of these.
It'll show on Safari, the
simulator and on device as well.
And now just to preview
on device,
I'm going to choose
Preview on Device.
It talks to you about what
you need to do on your device.
I've got an iPad that's
plugged in over here
and I'm just going to unlock it.
It's not very interesting
to see but it'll walk you
through the process
of maybe you need
to load the Tester
app on your device.
It'll go and install
that for you
and might ask you some
permissions in order
to get the debugger
hooked up to the device.
But I'm just going
to press OK here.
It's going to export whatever
I've got on the screen,
bundle it up, ship
it over the cable,
and move it over to the device.
And so, there's a little Widget
Tester application over here.
And if I'll go and I launch it,
you'll see when I do
this particular example.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I just launched it.
Now it's running on the device.
It's running here
on the desktop.
And you'll see that the
Web Inspector launched.
A bunch of detail over--
information over
here, I can hide that.
But you can see the
DOM that's generated,
the markup that's generated
when this was exported.
Lots of HTML goodness.
How everything is
categorized here.
All the scripts are put
together within the inspector.
And just to level set here.
We've had two incredible
sessions on the Web Inspector.
So I'm going to touch this
thing fairly light today.
But if you go back and
look at the videos we had
in Introduction to the
Web Inspector as well
as an advanced version of
that session and they're great
if you really want to get
in to the nuts and bolts.
But, you know, the idea of this
particular demo is to figure
out what was going on with
the sample and I'm going
to focus the bulk of my time
in this little Instruments
icon that's right up here.
So it looks like a
little stopwatch.
So I've got my sample
running here on the iPad.
The balls are bouncing
around as I would expect.
And the first thing
that I want to look
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
at are the network requests.
If you're building in iAd, you
know that you're pulling content
down from the network.
You're typically using
cellular data as well
and we know there's all
sorts of efficiencies
and inefficiencies associated
with cellular network
when it comes to latency
and those types of things.
You could be pulling
from a Wi-Fi network
or maybe you're just
pulling locally.
It's always good to get a feel
for sort of what, you know,
the-- what's the network
profile associated
with your Widget
or iAd gesundheit.
So, I've got network requests
setting here, so I'm going
to hit Start Recording,
this little button.
And then I'm going to
tell my widget to reload
to fetch all the assets.
So I'm going to do a Command-R
and then I'll see it
update here on my iPad.
And it's loaded.
It's done.
I'm going to press
Stop Recording.
And you can see all sorts
of very numeric specific
information associated
with the latency of these items.
But the nicest screen to
look at is basically this one
without all of the
numbers there.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And it gives you a really good
feel for the loading aspect
of your particular widget or ad.
You'll see a timeline
across the top.
And this purple bar is when
the load event was called
for this particular item.
And that's when it's presented
on the screen, and let's assume
that all the assets are present.
And that's the thing
that you want
to get as short as possible.
You want that load to be
called as quickly as possible
so people aren't waiting
around wondering why they're
looking at a blank screen.
And so if I look at this,
it says, "Oh, it's about"--
I don't know, 2.71, let's say.
And just to get a feel for
the rest of the content here,
you'll see the times associated
with downloading each one
of the assets as well
as how long it takes
to actually process
some of these as well.
And if you look at this
last file, this particle.js
which is the nuts and
bolts of all the animation
that you see spinning around
in that example was gadded
by this particular file
here, and this is a bit
of a contrived example.
If I look at it, I can see that
the thing is called lorem.js
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
which is, you know,
suspect to begin with.
And going up, there's this
other one called ipsum.css.
So that sounds pretty
suspect as well.
I mean it's kind of a silly
example but I think the point
to make with this is this
particular project has a bunch
of files better compressed,
thrown down to the device.
But there's a good chance
that you're still shipping
down to the device
extraneous files.
Maybe it's part of your
development effort,
you're using third
party libraries
or maybe you had other source
code trees that you were pulling
in and then you decided,
"I don't need those."
You're doing your
testing on the Mac.
You didn't see any sort
of performance issues.
But then when you go and
you look at the device,
it's taking forever for this
particular page to load.
So, always go and take at look
at the files that are here
and make sure that they're
what you actually want
because they all impact this
bar here to impact the load time
and you want to keep it as
short as possible as I said.
So clearly, I've got a
couple extraneous silly named
files here.
Another good example of
a best practice here,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
certainly in a cellular
network and in sort
of low bandwidth
areas is pulling
in a series of particles.
Each one of these are
the little molecules
that you see bouncing
around in that demo.
There is a separate file
for each one of these.
And one of our best practice is
when we're doing mobile
development is to take all
of those and combine
them into a single image
so that you're only waiting for
that one file, a certain amount
of time, but when
it comes you get all
of the images associated
with it.
So another good best practice is
to not only remove this
extraneous content here
but also take all
of those images
and combine them into one.
And I've got one of those
that's sort of pre-baked
as well which I can show you.
Let me go ahead and close this
and I'll pull up this one.
And so I've gone back,
I've optimized my project.
If I go and look
at the assets here,
it just has the one JS file
that's required for this.
This is where all
my code logic is.
Here's my particles.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
All put together
within one image.
And then if I zoom in a
little bit closer here,
you'll see that iAd
Producer allows you
to do this image spriting
technique with the single image.
So there I've selected
one of the beads.
If I go and look
at my Inspector,
you'll see that it's using the
same image for every single one
of these and it's just
computing an offset
or it's using an offset
within that particular image.
And you can actually see
it if I double-click in it.
All of these other
images are here
but we're just showing
a real slice of it.
So it's making one
request, pulling it down
and then just showing
a little portion of it.
It's great best practice.
All right, so let me go
back out to my overview.
And so, what's-- what
am I going to do next?
Well let's do a little
bit more sleuthing here.
Let me go back and preview
it on the device and see
if I have any gains,
and I bet I will.
Launches, comes back up.
It's running.
I'm going to hit Start
Recording, do a Command-R
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to relaunch, and Stop Recording
'cause it's completely loaded.
Now, look at the times here.
I mean it brought it
down significantly.
And although it was
a bit contrived,
it's still fairly significant.
Some of these files
that you'll use
or may use physics libraries,
those types of things,
in your ads or in your widgets
when you're building them
can take up a huge amount
of real estate in a
significant amount of time.
And there is just the one
image being pulled back
and then we're doing all the
right thing about spriting it.
So, I don't remember what
the number was before,
but this is probably a quarter
of the time that it was to load.
So the faster that you can get
content on the page, the better,
and that's what you want.
You want this bar to be
further and further down,
this number to be smaller.
All right, another thing
that we can take a look
at in this particular project
is sort of performance.
We can look for hotspots.
Where is this particular item
spending the bulk of its time?
Maybe it's getting a
little sluggish and, OK,
clearly something is going on.
Well, I can hook in
to the profiler here
and hit Start Profile.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And you'll see we have two
different options for profiling.
We can watch the JavaScript
as it's actually running.
See all the calls it makes.
We can do that for CSS selectors
as well and try to find
out what's going on, where is
something spending the bulk
of its time.
So I want to do a
JavaScript profile
in this particular example.
Hit Profile.
Now, it's going to run.
The balls are bouncing
around here on my device.
If this was a multi-page
add or multi-page widget,
then you'd want to start
doing some navigation just
so you got a good, you know,
coverage of the app while
you're doing your profiling.
But this is just
bouncing around.
It's a single page.
I'm going to hit Stop Profiling
and then select my profile.
And here is where-- I'll zoom in
a little bit so you can see it.
You'll see this little
disclosure item
where it'll show me
all the function calls
and how much time it's spending
within each one of them.
Right, so there's-- 100 percent
of the calls are being made
in this particular
program but I can also see
that there is this particle
simulation move particle that's
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
got the bulk of the
calls actually happening
and all the other numbers
there are relatively small,
and that sort of makes sense.
The bulk of the code being
executed right now should be
to move the little balls around,
so that makes total sense.
And if I drill in a little bit
more, you'll see that something
that doesn't make
sense is actually--
it looks like the collision
detection is being called a lot
more than actually the rest
of the code that's there.
It's all about calculating
how close it is to something.
And this is a real life
example that we run
into when we were trying to--
when the team was trying
to debug something.
It was doing all sorts of
inappropriate calculations,
spending way too much time
in this particular function.
And the way they found
it was they found
that it was spending the bulk
of its time in this call.
And if you go over and you
click on the line there,
it'll take you directly to that
call and you can review the code
and you can say, "I see it.
I was brain-dead.
I put the wrong, you
know, item in here
and this is why this
is misbehaving."
So that's what JavaScript
profiling looks like.
And taking a look
at network requests.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The next thing that I'll do
is I'll show you some items
on Instruments.
So Instruments, as Chi
Wai said, it comes--
it gets downloaded along
with the Xcode toolset.
So I've got Xcode
on this device.
But what's a little bit
frustrating if you're not used
to it is the fact that if you
go looking for Instruments--
I'll go into my launch pad here
and just type INS,
it's not found.
OK, I've downloaded Xcode.
Where is this silly tool?
Well it's actually embedded
within the Xcode bundle.
So the best way to find it,
certainly the first time,
is to go and use your
[inaudible] spotlight, type in,
launch it, and now you've
got Instruments launched.
And then you can do the
trick of saving it in the DOC
and then you can go and access
it multiple times whenever you
want to go and get access to it.
So this is Instruments launched.
And what we want to
do is take a look
at the memory profile associated
with this particular
demonstration.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And so, what I'm going to use is
this Activity Monitor instrument
that's here.
Always make sure that you're
targeting the OS here 'cause I'm
going to go and do the
profiling of the memory
as it's actually on the device.
Not a lot of need to
profile it while it's running
on the MAC or in the simulator.
So I'm going to choose
the Activity Monitor.
Place it there.
Now I've got in on the left.
And now all I need to do is
say, "OK, Activity Monitor,
I want you to monitor a
process that's running currently
on this type of device."
So under the process' dropdown,
you'll see there's
my iPad connected,
here's this machine as well.
I don't care about that.
With that iPad selected, I'm
going to go and choose a target.
So this is the process that's
on this particular device
that I want to connect to.
So I can go and I can look at
the memory profile associated
with my iAd or I can look at
the memory profile associated
with my iBooks widget, the
tool will perform the same.
So I'm going to choose
iBook's widget tester
because Chi Wai's
example is a widget.
Now I connect to that process
and what I want to do is come
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
into my pad and press Record.
It will go and launch
the widget tester.
And if you can see, it's got
some pretty sweet graphs here,
right.
And you can see some
traces about how much
of the memory is consumed and
that's fairly interesting.
But what's really interesting
is testing the memory profile
associated with my
particular widget or ad.
So now I'm going to
go and launch that
and you should see a
spike in memory here.
And that's expected, right?
There's a lot objects
being allocated.
And if I look at this
chart, it looks pretty good.
It looks fairly flat.
And that's actually what I want.
Once things settle
down a little bit,
I should see memory allocated.
It sort of gets free and then
it finds this sort of flat line
of coexistence on the platform.
And that's what you want to see,
maybe little bump here and then.
But if you see some
sort of incline,
that means you're
leaking memory associated
with your particular project.
Maybe things aren't getting
freed or you're just building
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
up arrays until they explode.
So this data down here,
it's a lot of data
and all we really care about
is our iBook widget tester
that we're taking a look at.
So if I spell it, i-B-o-o--
you'll see here,
I've zeroed down.
And now I've got
actually the raw data.
Instead of just looking
at a pretty chart up here,
you'll see that I can look
at the real memory as well
as the virtual memory.
And you just want to make
sure that these numbers,
even though they'll
bounce around a little bit,
they always hover within
a particular range.
And that range will vary
based on the content
that you've got on a page.
So, this is a great
best practice especially
if you're using WebGL
with a lot of vertices.
Depending on what you're
doing, you may have constraints
in memory if you're
building an ad.
There might be a cap
'cause you're running
in a shared memory space
with the application
that's displaying your ad.
You might have other
constraints.
Again, this tool is a great way
to look at the visual aspects
of how your memory is
being consumed as well
as the raw data associated
with it.
So that's it for Instruments
and the Web Inspector.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Let me turn it back
over to Chi Wai.
[ Applause ]
>> Thank you Mark.
With Instruments
and Web Inspector,
we know that we're not flying
in the dark when we run
into performance issue.
Now, let me give you a summary.
Very first thing,
always test on device.
Second item, always
test on device.
As I showed you earlier,
what you see
on a MAC simulation could
be with [inaudible] thing.
So, I'm going to say
it one more time.
Test on device.
So, with Web Inspector
it's really easy
to identify CPU hotspot
and we can also look
at the network traffic life.
And we can help by
doing image spriting
and also removing unused asset.
With Instrument, we can memory
the memory footprint on device
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and we can save some memory
by removing hidden element
by applying display:none.
So what we have learned today.
We learned that iBook widget
and iAd are just mini website
within an HTML, CSS
and JavaScript.
And we learned that we
can do customization
with the same exact technology.
I showed you how we can put
data from a remote server
and show the data in
a multi-cell object.
And lastly, we looked at Web
Inspector and Instruments.
You can do some powerful
performance analysis
with these tools.
With what you learned,
go download iAd Producer.
It's free.
It's fun. It's super easy
to create amazing content
with great performance.
For more information,
contact Mark Malone.
He's our iAd Technology
Evangelist,
also our awesome demo
person of the day.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
There is documentation
online and developer forum
in case you need help.
Here are some related sessions.
I mentioned earlier,
there is an Introduction
to iAd Producer happened
this morning.
The video should be
available shortly online.
There will be iAd Integration
session happening tomorrow.
There're two Web
Inspector sessions
that happened yesterday.
The videos should be
available online by now.
And if you are interested
and want to learn more
about Instrument, there's a
session tomorrow you should
definitely check it out.
Thank you for attending
this session.
I will see you around.
[ Applause ]