WWDC2014 Session 401

Transcript

X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> Good morning.
Welcome to WWDC and this
is "What's New in Xcode."
You guys saw a lot of
new stuff yesterday.
Today, we thought we
would take a deep dive
into a few specific
areas of Xcode 6.
Before we do, though, let's
take a look at what's happened
since last time that
we were here together.
I hope you guys are all
using and enjoying Xcode 5.1.
Since last year, one of
the biggest new things
that we added was
support for iOS 64-bit.
And you guys have done an
amazing job of adopting 64-bit
in your apps to take full
advantage of our latest devices.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We've also made significant
improvements to auto layout
in Interface Builder
and added new APIs
to make your own classes work
with Debugger Quick Look.
This fall we'll be
releasing Xcode 6
with an even more beautiful
and functional interface
to go along with OS X Yosemite.
Let's take a quick look at some
of the new features in Xcode 6.
First of all, we have a brand
new programming language
for Cocoa development
called Swift.
And Swift is exciting
enough on its own,
but we didn't stop there.
Playgrounds provide a live
and responsive environment
for you to develop code.
Whether you're exploring
new technologies,
like Sprite Kit physics
courses, or just playing
around with Swift
itself, you're going
to love the experience
of playgrounds.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to love the experience
of playgrounds.
Playgrounds also offer a
great learning environment.
The Swift language guided
tour is actually a playground
where you can try things
out right as you're reading
and learning about Swift.
And of course Swift is
fully integrated into Xcode.
Everything from code completion
to connect from source
in Interface Builder works
beautifully with Swift.
When you're working
in Swift, Xcode knows.
If you ask to see the
interface for a framework class,
Xcode will show it
to you in Swift.
And when you ask for Quick
Help, you get help in Swift.
Now, Quick Help actually
has another new trick.
Oh, that's not that build.
So we have another new
trick that works well
with Swift's inferred types.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with Swift's inferred types.
If you're ever curious about
what type is being inferred
by Swift, Quick Help
can tell you.
And you can freely mix Swift
into your existing
Objective-C applications.
We'll be showing you how easy
that is in a few minutes.
Now, let's talk about some
of Xcode's design tools
and the new features there.
You're probably all familiar
with using storyboards
to develop your iOS
applications.
And in Xcode 6, you
can use storyboards
to develop your OS X
applications as well.
In iOS, the new adaptive UI lets
you have a single storyboard
for your universal applications,
while still retaining
full control
over customizing your interface
for both the iPhone
and the iPad.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
for both the iPhone
and the iPad.
And if you use custom
fonts in your application,
you can now see them right on
the canvas in Interface Builder.
[ Applause ]
We have some brand new
editors in Xcode 6 too,
like the Sprite Kit Level Editor
that lets you visually
assemble scenes.
Xcode 6 has a brand new way
to localize your applications.
You can export all of your
localizable content into XLIFF,
which is the industry-standard
format that's understood
by a lot of translation
services.
And when you get those
translations back, just import
and Xcode will help you to merge
that new content right
into your project.
And with iOS 8's
support for frameworks,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And with iOS 8's
support for frameworks,
you can now build IB components.
Just by adding a few
attributes to your classes,
you can get them to show
up right in IB's canvas
and configure them
in the inspector.
We'll be showing
you how easy it is
to make your views
into IB components.
Now, Xcode 6 makes
debugging better than ever.
Often, when you're
debugging using queues,
it's not quite enough just
to see the code that's
running on the queue.
So in Xcode 6, we
now show you how
that block got onto
the queue also.
When you're developing
the new app extensions,
debugging support is
easy and automatic.
For example, if you're
developing a Today View
extension, just hit
Run in Xcode,
bring up Notification
Center on the device
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
bring up Notification
Center on the device
and Xcode will automatically
attach
to your extension for debugging.
Xcode 6 has some
brand new debug gauges
to help you identify
problems with disc
and file I/O, disc
and network I/O.
And View debugging
gives you deep insight
into visual problems.
We'll be showing you how easy it
is to identify and fix problems
with your view hierarchy
and constraints using
View debugging.
Xcode 6 has some all-new
performance features as well
that will help you to make
your apps faster and leaner.
Our premier performance
tool, Instruments,
has a brand new interface
with new workflows
that make it easier than ever to
analyze your app's performance.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Last year we introduced
Xcode Server,
and one of the biggest requests
that we got was for the ability
to customize what happens
when you're running
continuous integrations.
So in Xcode 6, we've
added support for triggers
that allow you to add custom
behavior to your bots.
And we've added support in
the XE Test Framework in Xcode
and in Xcode Server
for performance tests.
It's easy to make
a performance test.
You just wrap your
code in a measureBlock.
Performance tests let Xcode
measure the speed of your code
and tell you whenever it
has improved or regressed.
And in order to help you to
make your apps even faster,
you can now profile your
performance tests directly
in Instruments with just a
choice from this context menu.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in Instruments with just a
choice from this context menu.
>> Yes!
[ Laughter ]
[ Applause ]
>> It's the little
things, right?
Xcode also includes
all-new reports
that show you exactly how your
performance tests are doing.
And we'll be showing
you how easy it is
to start writing performance
tests for your projects
and using them to
make your apps better.
So that's just a
quick tour of some
of the feature areas in Xcode 6.
And now we'd like
to dive in deeper
and give you a detailed look
at a few of these areas.
To get us started with that,
let me introduce Daniel Dunbar.
[ Applause ]
>> Thanks, Mike.
This talk is called
"What's New in Xcode,"
and obviously the big new
thing this year is Swift.
I'm sure you're all
really excited
about this new language
we unveiled yesterday.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
about this new language
we unveiled yesterday.
And I imagine many of
you are wondering, "Well,
how quickly can I start using
this in my own applications?"
So we'd like to kick off
our demos this morning
by showing you just how easy
it is to integrate Swift
into an existing application.
We've created this new
photo scavenger game.
Let me show it to you now.
Our game is called Shutterbugs,
and when I open it up,
you'll see our game starts
with this great looking
sign-on screen,
and it takes the user
right into the game.
That's been working great,
but our app has really
been taking off recently,
and users tell us
they want to be able
to play multiple
games at one time.
So for Version 2, we'd like to
introduce a new games landing
screen that shows users their
in progress and completed games.
And of course we'd
like to do it in Swift.
Now, my designer has already
updated the storyboard
to include this table view
controller shown here.
All we need to do to finish off
this new feature is implement
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
All we need to do to finish off
this new feature is implement
the code for it.
So I know I'm going
to eventually want a custom
cell class for my table,
so I'll start with that.
Going to go to Views and select
New File from the popup menu.
Of course, I want an
iOS Cocoa Touch class.
And the first thing you'll
notice on this screen is
that there's a new language
chooser at the bottom
that lets you decide
whether you want a Swift
or an Objective-C class.
Of course I want Swift, and
in this case I want a subclass
of a UI table view cell.
I'll call it GamesTableView
Cell.
Drop that in my project...
and Xcode takes me
to the source.
These subclass templates are
a great way to get started
with the new language.
So for us, the main thing we'll
need is a couple of properties
that we can use to
connect our UI to.
So let me add that
to start with.
As you can see, property
declarations
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
As you can see, property
declarations
in Swift are very
clean and simple.
And we just needed to add
this IBOutlet attribute
so that we could connect to
it from Interface Builder.
Now that that's in place, let
me go back to my storyboard.
So I'll select my
prototype cell,
and I need to associate
the class with it.
If I pull down this menu,
you see that Interface Builder
has already recognized our new
class using our Swift
indexing support.
So I'll select GamesTableView
Cell.
Now, you may notice there's
a new module field here.
Another great way that Swift
improves the coding experience
is by associating
classes with the modules
that they are declared in.
That allows you to use short,
comfortable class names
while still ensuring
that your classes won't collide
across targets and projects.
With that in place we can
set up our connections.
I'll close the Utilities
panel and open our source code
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I'll close the Utilities
panel and open our source code
in the Assistant Editor.
And now I can wire up
my connections just
like you would expect.
I'll set the name,
the state label,
and we have a custom
progress view here.
OK, that should be enough
to let us get started
with our custom cell.
So now let's fill in the
details of the controller.
I've already added the
basic subclass template
with a couple tweaks, but we
need to fill in the details.
So the first thing that every
controller class needs is access
to the model data that
it's going to present.
For our application, most
of our model data is stored
in a user session class.
So let me add a property
to hold that now.
So I'll call it userSession
and declare its type.
Naturally, we have live
issue support in Swift,
and if I pop this open I can
see it's telling me there's an
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and if I pop this open I can
see it's telling me there's an
undeclared type here:
userSession.
I haven't imported
that class yet.
Now, in Swift, all
of the classes
in one target are automatically
visible to each of the source --
the Swift implementation files.
You no longer need to worry
about manually importing
the headers for each
of the classes that you use.
[ Applause ]
Yep. However, you do still
need to import the modules
for the frameworks
that you depend upon.
To go along with iOS 8's
new framework support,
Xcode now has support
for you to define modules
out of your own frameworks.
And those modules can be used
in both Swift and Objective-C.
But we've already started
taking advantage of that
in our application by
moving all of our model code
into this new CoreShutterbugs
framework that you can see.
That means, to use this
-- fix this problem,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
That means, to use this
-- fix this problem,
all I need to do is type
Import CoreShutterbugs just
like I would for any other
framework on the system.
And of course the
error goes away.
Now, our table view is going
to have two different sections.
We'll have one for the
in-progress games and then one
for the completed games.
So I want to start by
creating a utility method
that lets me easily get
the appropriate list
for each section.
I'm going to call it
gameListForSection.
And what I want to
return here is the result
of the user sessions
"getFilteredGameList" method.
You can see that even
though this is a method
that we declared in our
Objective-C source code
in another framework, I
still get code completion
and even the documentation
for that method
in my Swift source code.
So I'll complete that out.
And what I want to get
is the in-progress list
when the section number is 0.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I'm also going to add a
cast here to a game array.
What I'm doing here
is taking advantage
of Swift's typed collection
support to tell the compiler
that each object in this array
is an instance of my game class.
That way, whenever I use
this array later in the code,
the Swift compiler will know
the exact type of each object.
There's one more
utility I'd like.
In a table view you frequently
want to get the data associated
with a particular cell, and
that cell is represented
by an index path.
So I'll create a method that
lets me easily get the game
for a particular index path.
Going to call that
one gameForIndexPath,
and it returns an optional game.
With those methods in
place, should be easy
to write our table
view data source.
Let me drop that in.
What I'm doing here: setting the
number of sections to be 2...
I'm going to return an
appropriate number of rows
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I'm going to return an
appropriate number of rows
for each section using that
first utility method we added,
and I'll use gameForIndexPath to
easily get the particular game
and then propagate its data into
our custom cell whenever we need
to dequeue a new cell.
I've also added a
prepareForSegue method to set
up our destination
view controller
when the transition happens.
OK, we're almost done, but I'd
like to do one more thing before
we call our controller a wrap.
You can see that I'm already
modifying the separatorInset
on this table to give our table
a little bit of a custom look.
That's all right,
but I just heard
about iOS 8's new
Separator Effect property,
so I'd like to try it out here.
I know that it's called
"tableview.separatorEffect,"
but I can't remember the
exact object that I'm supposed
to assign to that property.
In Xcode 6, if we jump to
Definition, it'll take us right
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
In Xcode 6, if we jump to
Definition, it'll take us right
to UITableView, but
it's rendered in Swift.
Even though this is actually
an Objective-C header
in the system framework, Xcode
has dynamically translated it
to the Swift interface just
like the compiler would see.
And even though this is
happening on the fly,
we take great care to preserve
all of the API comments
that you need to use these
libraries effectively.
Now that I'm here, I can see
that separatorEffect
is a UIVisualEffect.
And if I navigate
onwards to that?
Ah, now I remember.
What I want is a
UIVibrancyEffect, and I'm going
to use a Dark blur
style to go with that.
So let me add that to my code.
Now, when I go to
specify the style here,
I'm going to take advantage of
Swift's advanced type inference,
and that lets me
just type ".dark".
The compiler is going
to automatically infer the right
enumeration type to use here
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to automatically infer the right
enumeration type to use here
because it's obvious
from the context.
That saves me having to type
the full enumeration name
and can really save
a lot of typing.
OK, that should do it
for our controller,
but there's one last
thing we need to set up.
Remember that UserSession
property
that I started off by creating?
We've never initialized
it anywhere.
So to fix that, let's
take a very quick look
at the other side of
Swift development:
using your Swift classes
inside Objective-C.
The place that we want to
initialize this object is
in the sign-in controller's
prepareForSegue method.
And if I go to Sign-in
Controller,
you'll notice this is
an Objective-C file.
And of course in Objective-C
before you use your classes,
you need to import them.
But our class is defined in
Swift, so how can we do that?
Well, when you're using
Swift in a target,
Xcode will automatically
generate a new header for you
that contains the declarations
of each of your Swift classes.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that contains the declarations
of each of your Swift classes.
All that you need to do
to use those classes
is import that header.
For this target it'll be
called Shutterbugs-Swift,
and I've added the Import Now.
You'll also notice
I'm taking advantage
of the at-import
syntax in Objective-C
to import my own
CoreShutterbugs framework.
So with those in place
I can fill in the rest
and prepare for segue.
I get the Games View Controller
and I'll set its
userSession property.
What you'll notice is that even
though GamesTableViewController
is a...
Swift class that we just
defined, we can use it
in Objective-C just
like any other class
and we can assign this property.
And if I came back
to this code later
and I'd forgotten what the type
was, I can even use Quick Help
to get the view as
Objective-C would see it,
and it even includes the
description of my property,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and it even includes the
description of my property,
even though I only ever
wrote that one place
in my Swift source file.
So with those in place,
let's see how it looks.
I'm going to build and run,
and Xcode will launch our app
in the iPhone 5s simulator.
There's our great
looking sign-on screen.
And if I click through
to play Shutterbugs...
There you have it.
A new landing screen
completed entirely in Swift,
and with this great-looking
vibrancy effect to boot.
[ Applause ]
We've integrated Swift
support throughout Xcode 6
so that you can use the same
great development features
that you're already familiar
with to immediately start
working with our new language.
And with that, I'd like to turn
things over to Jon Hess to talk
to you about our brand new tools
for visual interface
development.
Thanks.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[ Applause ]
>> Thanks, Daniel.
I'd like to show all of you
how you can take advantage
of the new features of Xcode 6
to design the visual
aspects of your application.
Let's head over to
the demo machine.
I have a spec from my designer
to implement a circular
image view.
It's going to take a
square images input,
crop it to a circle, and
optionally desaturate the color.
Now, I'm finding Xcode's
new playgrounds feature
to be indispensable when
working on features like this.
I love being able to see
the results of my code side
by side as I write my code.
I have a playground
set up just for this.
It starts with a sample image,
and you'll have a basic function
to manipulate a graphics
context and return a new image.
I'm going to paste
in a bit of new code.
It will take an input image,
optionally desaturate it,
and two sample calls
to render my image.
Here in the Timeline I can see
all of the results of my code.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Here in the Timeline I can see
all of the results of my code.
And by pressing this button,
I can bring in a persistent
preview of any of the values.
That's our starting image...
and here's the two outputs.
Right now all three
look the same
because I haven't done
anything to process the image.
I'm just taking my source image
and drawing it raw
to the destination.
OK, the first step is
to crop to a circle.
I'm going to create a Bézier
path with an oval inscribed
in our square, add that
to the clipping path
and now we have circular images.
Things look good.
I'd also like to
desaturate my image.
I'm going to simply wash
over it with a white color
and use a special core graphics
blend mode that subtracts
out the color instead
of adding white on top.
And now you can see that
our third call produces a
desaturated image.
Things look great.
I'm ready to start using
this in my application.
Going to grab a copy of this
code and head over to my class
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Going to grab a copy of this
code and head over to my class
that I've been working on.
Here's my prepareImage function.
It's not implemented yet.
I'm simply going to paste in
my code from the playground
and I'm ready to start
using this in my storyboard.
I'll option-click here to
open it in the Assistant.
And down in the lower
left corner you'll see the
square view.
This is where I'd like my
circular image view to be.
In Interface Builder's Inspector
I can see this is still an
instance of just regular UIView.
I'll type, Interface
Builder will autocomplete,
and you'll see it filled
in the module name as well.
My circular image view class
is defined in a framework,
while my storyboard is
in the main application.
So the module name and the
class name together complete the
reference to my class.
Now, I've still got
a white square here.
At this point Interface Builder
is doing what it's always been
capable of doing.
It's saying this UIView
will be an instance
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
It's saying this UIView
will be an instance
of the circular image
view at runtime.
In Xcode 6, we can
make it an instance
of the circular imageView
at design time as well.
Let me show you how to do that.
We've added a couple of
new source attributes
that you can add
to your classes.
The first is IBDesignable.
It goes right here at
the top of your class,
goes in the same
place for Objective-C,
spelled a little
bit differently,
but it has the exact
same result.
Interface Builder is
able to take our class,
build our framework,
instantiate it,
and render it live
into the canvas.
You can see it here.
Now, you may be wondering,
"where is that silhouette
coming from?"
Down here in my source file
I've overridden a new method,
prepareForInterfaceBuilder.
This is going to be invoked on
our view right before it renders
into the canvas, and it's
a last minute chance for us
to do any additional setup.
Here, I'm simply making sure
that we always have
an image prepared.
Now, I'd like to just
configure my image directly
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now, I'd like to just
configure my image directly
in Interface Builder, and
option in my saturation as well.
No problem.
We have another new source
attribute: IBInspectable.
I can put it here in front of
my property, and when I return
to Interface Builder
I can see in Inspector
that they have two new fields
that've directly derived
these values.
Let's pick another image.
All right, that looks great,
but when the user comes here,
I'd like them to be focused on
this photograph, not distracted
by the bright colors
in this player image.
That's where our
saturation comes into play.
Let's tone this down a bit.
You can see the canvas
is updating right away.
And things look good.
Let's make sure it looks
good with another image.
Oh, yikes, she got squished.
I'm not sure what's
going on here,
but I suspect it probably
has something to do
with my prepareImage
function that I just wrote.
I'm going to go ahead and
put a breakpoint here.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And with my view selected, I
can choose Debug Selected Views.
Interface Builder is going
to kick off a request
to render this view
live in the canvas
so that I can see
just what's going on.
[ Applause ]
Now, I'm not sure what
the problem is here,
but stepping into the code...
Oh, actually I can
see it right away.
Bringing up the Quick
Help -- the Quick Look --
on this rectangle, I can see
it really is a rectangle.
It's much wider than it is tall.
And interface Builder is
taking that rectangular image,
or my view is, and squishing
it down into that square
and we're getting
this crushed image.
I think what I want instead
is to produce a square image
and draw the source image
centered in the destination.
Interface Builder is going
to automatically pick
up my changes, re-render
the canvas...
and I can see we're in business.
Things look great.
All right.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I'm done with this scene.
My next set of steps after
this is typically to head
over to my iPad storyboard and
make much the same set of edits.
Let me close this out...
head over to my iPad
storyboard...
and [sighs] I can see that
I have a lot of work to do.
I haven't even started
on this scene yet.
No problem.
Xcode 6 solves this
for us as well.
We have a new feature, Universal
Storyboards, that allows us
to build a single storyboard
to target both the
iPad and the iPhone.
I'm going to head back over
to my iPhone storyboard.
[ Applause ]
Thank you.
And I want to show you just
how easy it is to get started
with Universal Storyboards.
In the File Inspector there's a
new checkbox, Use Size Classes.
I'm going to go ahead
and enable them.
Size classes are a
foundational new technology
that form the underpinnings
of the new adaptive user
interfaces in iOS 8.
With size classes, I can
customize which views
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
With size classes, I can
customize which views
and constraints participate
in each of my layouts.
Adopting size classes also
upgrades all of the segues
in my storyboard to their
new adaptive counterparts
from iOS 8 -- segues
that, for example,
know to present a
popover on the iPad
and a modal transition
on the iPhone.
Now, you can see Interface
Builder is rendering my canvas
here as this square.
This is an abstract
representation that's meant
to remind you that you're not
editing for a specific device,
you're editing for all devices.
If I want to see how things
look on a specific device,
I can open the Enhanced
Preview Editor in Xcode 6.
Here you can see that auto
layout does a great job
of translating my interface to
the screen of a 4-inch iPhone.
I can zoom out and I can
add more screens as well.
Here's how my interface
will be presented
on an iPad in portrait.
And you can see as well
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And you can see as well
that auto layout has translated
my screen all the way up.
But I had a custom
layout just for iPad.
How do I achieve that
with this new feature?
Well, let's get started.
The first order of business is
that this top bar
should be short.
I'm going to go ahead
and shorten it up
and tell Interface Builder
to update the constants
of all my constraints from
the frames in the canvas.
And, well, you can see
they both got short.
Well, I'm editing both
interfaces at once;
it's a universal storyboard.
How do I edit just one of them?
Let me undo this change.
Down here in the bottom center
of the canvas is a new control
for picking which size
class you're editing within.
Right now we're editing
the size class
for Any width at Any height.
It's the basis for all of them;
all layouts inherit from this.
It's represented as this
choice here in the center.
As I move away from the center
things get more specific.
Down here in the bottom right
corner is the Regular width,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Down here in the bottom right
corner is the Regular width,
Regular height layout.
It's the largest, and it's
the basis of my iPad layouts.
I'm going to choose it,
and Interface Builder enlarges
the canvas to remind me
that I'm working in a
specific size class now.
Let's go ahead and make
that bar shorter again
and update the constants.
And now you can see that the
iPad has changed while the
iPhone has remained just
the way that I designed it.
Down here in the bottom left
of the scene I have a
completely new layout in mind.
Rather than just editing
the constraint constants,
I want new constraints.
No problem.
I'll select all three
of these views
and have Interface Builder
clear the constraints
in only this size
class and reposition.
I'm going to have the
image front and center.
Hmm, right about there?
Maybe a little lower.
And I've sized this
image view arbitrarily.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And I've sized this
image view arbitrarily.
I need to pin its size.
I'll start with an
explicit width constraint.
And now I've said that the
width should be, you'know,
some constant -- whatever this
happens to be (120 points).
I want the height to be the
same, but rather than duplicate
in the constant,
new since last year,
I can add an aspect ratio
constraint saying the width
and the height should be equal.
[ Applause ]
[ Background Sounds ]
[ Laughter and applause ]
Ahh...!
[ Laughter ]
I could continue those edits,
position the views underneath,
and have Interface Builder
add the remaining constraints
to produce an iPad
layout that was unique
to the iPad interface,
while maintaining my iPhone
layout just the way that it was.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now, I'd like to turn it over to
Ken Orr to tell you what's new
with debugging in Xcode 6.
[ Applause ]
>> All right.
Thanks, Jon.
Good morning.
So I've just taken over
the photo details screen
from another engineer on our
Shutterbugs team, and I'd love
to give you a sneak
peek of that UI now.
OK, so the first thing I'm going
to do is I'm going to run...
and then we will sign
in to the game...
I'll navigate to this
in-progress game, and I'm going
to click on this
particular picture.
And then here we are at
the Photo Details UI.
So what we're seeing in
this case is a picture
that Paula took.
We see a list of all the other
players in the game along
with comments they've made
on this particular photo
and whether they like it or not.
And, you know, as I
look at this UI here,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And, you know, as I
look at this UI here,
I'm a little bit
skeptical that all
of these players are
missing their picture.
So they're all showing this
kind of placeholder image,
and that's not something
I'm expecting to see here.
So let's go ahead and
let's dig into that.
Now, I'm relatively new to
this code base, but I do know
that our problem here,
it's going to be in
one of two places.
So it's either going to be
on the model side of things,
that maybe the image data just
isn't there, or it's going to be
over on the UI side of
things: We have the image data,
but we're not pushing
it to the screen.
So we want to figure out
exactly where that problem is.
So the first thing I
need to do here is figure
out what view controller is
responsible for this view here.
And I think it is this guy,
photoDetailViewController.
So what I want to do is I
want to set a breakpoint
in this view to appear.
And then let's try to
trigger that and see
if we are in the right place.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
if we are in the right place.
We'll navigate away, we'll
come back, and there we go.
OK, we hit the breakpoint, good.
So we're probably
in the right place.
But I'd like to be really sure
that we're in the right place.
And I'm going to do that by
using the brand-new Quick Look
for UIView in Xcode.
So now I can just mouse
over this view here
to get the data tip,
which is the view owned
by this view controller,
and I can click
on our little Quick Look button.
And just like that I
can see a rendering.
[ Applause ]
Yeah. I can see a rendering
of this view or any subclass
of UIView right here in
Xcode while I'm stepping
through my code.
And of course if you're
developing a Mac app,
this works great for NSView too.
All right.
So now, step one complete; we
know we're in the right place.
Good. But what we care
about is the model objects.
And I think our model objects
are these GameComments.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And I think our model objects
are these GameComments.
Looks like we have a GameComment
for every row of data here.
So these rows are
backed by a GameComment.
Now, when I'm debugging, I
really love to use Quick Look.
I'm a really visual guy.
Quick Look is a really great
way to visualize my objects
when I'm stepping
through my code.
Wouldn't it be great if we
could have custom Quick Look
representations for
our own classes?
Well, in fact, now inside of
Xcode you can do just that.
And we've gone through
our project
and done it all throughout
our classes.
Let's see if we have
one for this GameComment
that we're investigating.
And sure enough we do.
And what we'll see is
that somebody's implemented this
new debugQuickLookObject method.
So this is a method that you can
implement in your own classes.
And it's a method
that Xcode will call
when you initiate a Quick
Look from the debugger.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now, from this method
you can return anything
that has a built-in
Quick Look inside Xcode.
So maybe an image, or a
Bézier path, or a string,
or in this case an attributed
string, which is going
to let us have a little bit
more complex visualization.
So we're going to be able
to take text and an image
and put those together
in a nice visualization
of our model object.
Now, I'm really curious.
I want to see what this
actually looks like.
So let's go back to where we're
paused and I'm going to mouse
over our GameComments array.
I can see that there's three of
them, which matches what I see
on the screen; that's good.
And then I'm just going to press
the Quick Look button, and,
boom, just like that, I'm seeing
my model object exactly the way
I wanted to see it.
[ Applause ]
And of course we can
arrow down through these.
Annnd... great.
So now we know we've
eliminated the model
as being our source
of our problem here.
We can see the player
image is right here,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We can see the player
image is right here,
so we know it's not
a model side issue.
So let's get rid
of this breakpoint
and let's continue onward.
OK, so the issue must be up
here in the UI, and, you know,
whatever view is responsible
for drawing this bit
of UI isn't doing its job.
Now, like I said, I'm
new to this code base.
I'm not really sure what
views are responsible
for pushing these particular
pixels to the screen.
So how are we going
to deal with that?
How are we going to
debug this issue?
Well, Xcode 6 introduces a brand
new way to visualize your app
when you're debugging.
So you can press this new
Debug View Hierarchy button
right here.
And Xcode will pull
in a representation
of your entire view hierarchy
right inside of Xcode
where you can see things like
snapshots of all your views,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
their frames, and all sorts
of other interesting
properties that...
when you combine them together,
they help to give you a
really great understanding
of why your app looks
the way it does.
Or maybe more importantly,
why it doesn't quite
match your expectations.
So I can, for example, let's
click on this label here
and open the Inspector.
And I can see that
this is a UI label.
I can see its text.
I can see its font.
I can see its font color.
All the things that I'm used to
seeing when I'm designing my UI
in IB, well, I can
see those right now
when I'm debugging it as well.
Really, really powerful.
So what we care about, though,
is this little picture
right here.
So let's select that guy.
And what I'm interested in
seeing is what cell owns
that picture, so what cell
is probably doing the wiring
up of the model data
to the UI controls.
Now, I can use Xcode's jump bar
to see the entire view hierarchy
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now, I can use Xcode's jump bar
to see the entire view hierarchy
of the selected object, and
so I'm going to go up here
and I'm going to see that...
that view is in this
gameCommentTableView cell.
So let's find that over
here in the navigator,
and it's this guy, OK.
Looks like a very simple class.
It has this useGameComment
method
which takes the model data, and
then it looks like it wires it
up to the UI controls.
So what I see here is I see
that the player's name is pushed
into this player label.
I see that the comment is
pushed into the comment label.
What I don't see is I don't
see us taking that player image
and pushing that into anything.
So that's probably
our problem here.
And it was really easy to find
that using Xcode's
new View Debugger.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So I'll go ahead
and fix that later.
And that is probably
going to take care
of this missing image
that we're seeing.
But, you know, as I
look at the UI here,
it doesn't quite match the
design that I was looking
at earlier with my designer.
So there's supposed to actually
be a little button right
around here in the
bottom left of the picture
that lets me like this image.
So I'm supposed to come
to this UI and say,
"I like Paula's picture."
But right now I can't do that.
Now the question then
is where is that button?
Well, maybe the button was never
added to the view hierarchy.
Maybe it's hanging out
off-screen somewhere.
Maybe it's the wrong size.
Maybe its alpha component
is wrong.
Maybe it's hiding
behind another view.
There's all sorts of really
visual kinds of problems
that we could have
with this control.
And they're all made
really easy to track
down with the new View Debugger.
So let's go back over here
to Xcode and let's look
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So let's go back over here
to Xcode and let's look
at our view hierarchy again.
So what I want to do
now is I just want
to explore this view hierarchy.
I want to look through and see
if that button is in fact here.
So the first thing I'll
do is I'll just sort
of twist this guy sideways.
I want to peek behind
some of these other views.
[ Applause ]
Sure. And then I want to
pull these views apart.
So let's do that and, hey,
I see a little something
peeking out right back here.
That could be our button,
but there's still
some stuff in the way.
So I want to peel back some
of the views in the front
so I can just hide things
from the front backwards.
Yeah, very nice.
[ Applause ]
And sure enough our button
is hanging out right here.
So let's select that.
And the next question
I'm asking myself is,
"Why is our button down here?"
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
"Why is our button down here?"
And I know we're using auto
layout in this project,
so I'd like to look
at the constraints
that we're using here so
I can show the constraints
for this particular view.
And just like that, Xcode
hides all the other views
that aren't relevant and
shows me just the constraints
for this particular control.
[ Applause ]
And we can really easily see
that the button is pinned
to the bottom left, which
is not where we want it.
We want it pinned to the
bottom of the picture above.
So that's something that
might be really hard to track
down before but is really
easy to track down now.
OK, so with Xcode 6, as we've
seen, you have the ability
to visualize your app
when you're debugging
like never before.
You can create custom
Quick Look representations
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You can create custom
Quick Look representations
of your own classes that show
your data exactly the way
that you want to see it.
And view debugging, well, that
adds an entire new dimension
to the way you can
explore and interact
with your app at runtime.
Really, really powerful.
And I think you're going to find
it really insightful as well.
And with that, I'd like to
turn it over to Kate Stone
to talk a little bit more
about how we can enhance
the performance of our app.
Thank you.
[ Applause ]
>> Thank you, Ken.
It looks like we have
a spectacular game
coming together.
We think our users are going
to be really happy with a lot
of these new features...
if we can just make sure that
we ship a quality product.
And of course that's
the last piece
of the development process, is
to make sure that what we're
about to send out into
the world is going
to live up to expectations.
My team has done the right
thing every step of the way.
We've tried to make sure that
what we have is a product
that is high-quality because,
of course, we've got a set
of unit tests that
are running on this.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of unit tests that
are running on this.
So I've got the product
up and running.
I can go to my Test navigator.
And the Test navigator shows
that I have several
suites of unit tests here.
So I can go ahead and
run those one last time,
make sure that when the
game comes up we put it
through its paces, we're
green across the board.
Looks good.
From a functional perspective,
the game is doing
exactly what we expect.
And that's great because I've
got one last change I wanted
to make to the game.
I was thinking about
tinkering with some new filters
to give a little bit
more life to our images.
And specifically here,
I've taken advantage
of a Swift feature to
let me build an extension
to the UIImage class.
So I can take an existing
class and add the ability
to apply filters to it.
And so I have a variety
of filters here.
The "vignette" filter is one I
was thinking about toying with.
So maybe I should go ahead
and build one more test,
but this time a performance test
to make sure it's going to live
up to my expectations.
It's straightforward.
All I do is go and
ask for one new file,
pick the test case class you're
probably already familiar with.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
pick the test case class you're
probably already familiar with.
I'm going to go ahead
and use Swift for that.
And you'll note that of
course like all templates,
I have that choice of Swift or
Objective-C, but Xcode knows
that I've been using Swift
throughout the conference,
so it's the default for me.
I'm going to call
this "PerfTests,"
put it in my existing
group with my tests
and let Xcode create
that file for me.
So now I have what
should be fairly familiar.
It's got the usual setup
and teardown methods,
but written in Swift.
It's got a functional test.
We're not focused on
any of those today,
so I'll just set
those aside and focus
on the one new method
that's been put in place:
the ability to test
for performance.
So I'm going to
testFilterPerformance here.
And all I need to do is fill
in this measureBlock call.
Now, you saw the Objective-C
syntax on a slide earlier.
The Swift syntax
is really clean.
It's just a call to measureBlock
that passes one trailing closure
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
It's just a call to measureBlock
that passes one trailing closure
that does the actual work.
And so in this case for my work,
I'm going to go ahead and fill
in a test image (I'll pick
up one of the player images)
and then go ahead and apply
a vignette filter to that.
But the vignette filter's
not part of my test project.
So, again, we're getting a
live issue here, reminding me
that I don't have access
to that class directly.
So all I need to do is
import the Shutterbugs module
and I have everything I
need to exercise the test;
indexing has found the
test; I'm one click away
from building my project
and running that test
and seeing just how
long this takes.
It's going to run it a
number of times to figure
out how long it takes and
whether there's any variation.
And when it's done, it will
tell me exactly how long it took
to run and what kind of
standard deviation I'm seeing;
4 percent in this case.
So I'm getting pretty consistent
run-to-run timings on this.
Sounds good, but it's
taking a little longer
than I wanted it to.
So what I'd really like to
do is twist this open and see
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So what I'd really like to
do is twist this open and see
that I haven't set a baseline.
I haven't set a target
for my timing,
and I really wanted the target.
I wanted something
that was snappy to live
up to our users' expectations.
So I can go and establish
a baseline either based
on what I have now, or I can
go in and edit that and say,
you know, 0.25 seconds is
more what I had in mind here.
And now I'll get a reminder
every time I run this test
that I'm not living
up to expectations.
This test is going to fail red
because it wasn't fast enough.
Well, we could take time
to tinker with that,
but I did apply a number of
different filters as extensions
to UIImage here, so
let me just go back
and choose another one of these.
I'm going to use
the noir filter.
Rebuild, retest and make sure
that that's meeting
expectations.
Looks good; we're all green.
So across the board we're
in great shape to
ship this product.
But what if I'd had a problem
that I wasn't able
to take care of here?
What if I had a performance
issue I needed to investigate?
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
What if I had a performance
issue I needed to investigate?
Well, of course Instruments
is the answer
to all such questions.
Instruments is a great
way to get more detail
about what's going
on in your project.
So I'm just going to bring up
a context menu for this test
and choose to profile that
particular filter exercise.
Behind the scenes,
we're going to go ahead
and build specifically
for profiling
and launch Instruments.
And now we get our first glimpse
of the new Instruments UI.
Instruments has been overhauled
dramatically this release,
both to be consistent with
the new OS X Yosemite,
but also so that it's
more familiar for people
who are comfortable
with Xcode already.
We start off with
the Template Chooser.
Here, I can see at a glance
what device I'm targeting,
what I'm planning on running,
and find the right template
to exercise what
I'm looking for.
And I'm just going to look
at memory in this case.
I can look at what I've
been using recently or pick
from the complete list.
When I choose that template, I
then go into Instruments proper,
and the Instruments main window
is also dramatically overhauled.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and the Instruments main window
is also dramatically overhauled.
You'll see a few
things at a glance.
One is if it's not
immediately recording.
How many times have
you chosen a template,
found that it starts recording
immediately, stop it, go back
and tinker with the settings?
Now we give you an
option to go in
and change those
settings before you record
or to go straight to recording.
So what I'd like to do is
be able to browse through
and make sure that I've
got the settings I want.
And you see that the settings
are now all centralized
in the Inspector, again, for
familiarity for Xcode users.
So I can make sure that my
allocations instrument is set
up the way I want, my VM Tracker
is set up the way I want.
And when it's all good, I go to
the new, overhauled toolbar --
sleeker, cleaner, taking
up less screen real estate
than ever -- to start recording.
And we start recording.
And as always, Allocations
is tracking everything that's
going on.
We're getting a recording
of all the malloc regions,
all the Objective-C objects,
everything we could
possibly want.
We could go in and look at that
in a little bit more detail.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Perhaps we'd like to filter
down to a subset of this.
Well, filtering is now just
a simple click and drag;
no modifier keys needed.
[ Applause ]
So I can see all kinds of detail
about all kinds of objects,
but I can narrow in on something
like my PerfTests class.
I know that was allocated.
And of course Swift objects are
represented alongside everything
else here.
We can see the module
name as well
as the class name
and get details.
So that I can see for this
particular class what instances
were allocated and when
that instance was allocated,
what stack trace that
instance came from.
So a ton of detail
right at our fingertips.
And of course that carries
over as well, but if I want
to look not just at
individual objects
but overall statistics -- where
are objects coming from --
I can see that I'm allocating
about 15 megs total during the
process of bringing the app up
and running the tests.
So what part of that is
actually in my applyNoirFilter?
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Well, I'll go ahead and
filter down and we can see
that it's just about
430 K that we're taking.
That sounds reasonable,
and indeed my stack
trace here is showing me,
highlighted in black, my
code so that I can see
at a glance where it is.
And rather than drilling down a
step at a time, I can just click
on my code and see where in the
stack trace that's occurring
and look in detail
at what's going on.
So Instruments, again,
the perfect way to dig in
and understand more
deeply what's going on.
We hope you will come to a
session later this afternoon
to learn more about it.
And that brings us
back to Xcode.
Everything's working
the way we want.
Of course my next
step is to check in.
And when I check in,
Xcode Server is going
to start doing its work.
And we can see that
we have a server set
up that my team has been using.
It's the perfect way
for a small group
of engineers to work together.
And we've got overviews here of
what's going on in my project.
So I can see recent
activity, my success tree,
(which is looking good,
we're being successful)
and my complete history --
off to a little bit of
a rocky start initially,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
off to a little bit of
a rocky start initially,
with one failed build, but
all in all looking good.
And our unit test
count is creeping up.
I can see historically
what failures occurred
so I might be interested in
digging into some of that,
but I'm really most interested
in my most recent integration.
And so if I drill down to
that integration and look
at all the tests
that are running,
I could see that I'm not the
only one who's been doing
performance tests.
Because beside my
green checkmarks here,
I'm also seeing variance
from baseline.
So at a glance, I can
see for this last run
that we're doing well against
the baseline in a couple
of tests that my
coworkers have been adding.
Looks great.
Let's twist one of those
open and see, in fact,
that we're tracking baseline
against individual devices.
So as we exercise it
in all devices we have
individual targets,
perhaps for different
generations of hardware.
And I think these
numbers are great,
but I want to make sure we
don't slide from here either.
So I can go in and edit
that baseline right there
and accept the last run
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and accept the last run
as the baseline target
for all future runs.
This is spectacular because it
means that -- for my machine --
I can change the baseline,
push that back to the server,
and that baseline
will be updated
on all my coworkers'
machines so they're measuring
against the same
targets that I am.
So I think we've got a
spectacular round-trip process
here for you.
You're going to love it.
And to wrap things up, I'd like
to turn it back over to Mike.
>> Thank you, Kate.
OK, that's Xcode 6.
The seed is out there available
to all of you, so try it out
and please let us
know what you think.
This is going to
be a great week.
We have a ton of sessions that
will go into even more detail
about all of this stuff.
Have a great show.