Transcript
[ Music ]
>> Hello, everyone.
[ Applause ]
>> Oh, please.
My name's Woody.
I work in software
engineering at Apple.
I'd like to welcome
you to the conference,
both those of you here in
the room and those of you
who are watching from
home on the live screen.
There's a couple things I'd
like to go through with you
in the next 40 minutes.
We're going to take
a look at some ways
that you can today start
reducing your technical debt.
Then, we'll take a
look at Asset Catalogs.
We'll take a look at
the new design pattern.
Well, it's not really new but
a design pattern we'd like you
to start using called
Dependency Injection.
And in the latter half of the
presentation will be an update
And in the latter half of the
presentation will be an update
from my presentation last
year about Live playgrounds.
So, let's get going.
Last year in the session at one
of the labs, I met one of you
that was describing a scenario.
You were describing something
that I think is going
to be quite familiar
to many of you.
You've got your boss that's
piling on these requests
for features and the features
generate revenue and you want
to get paid, so you do that.
Then you've got your
customers and they want
to fix the bugs that
cause them pain.
And you take pride in your work
so you want to do that too.
Some technical debt that
you want to resolve.
Sometimes I think about building
software as like building
up a pile of Jenga blocks.
In the first version,
it's pretty stable
and you start piling
on stuff on top of it
and then it becomes unstable and
begins to fall down after that.
So, you want to take a step
back and maybe resolve some
of the lower-level issues.
With all these things,
you then come to WWDC.
And we pile on new API.
And then we give you
a new version of Swift
and it breaks source
code compatibility
but introduces some
new features.
And you were warned, so
don't complain about it.
And then we introduced
new platforms
and new extension points and
some of our existing apps
like Siri and Messages.
And if you want to think of your
role as a developer as a bit
of a run loop with all these
events being pushed into it,
well, you know what
happens then.
There's too much stuff.
So, what you do?
What are some things
that you can start doing
to get ready for the fall?
First of all, if you were to
support a deployment target
of iOS 8 and 9, you would
cover 95% of the devices.
So, there's really no
need any more to have any
of those deployment
targets set to 7.
Let's get rid of that.
In fact, the general idea is
that you take the current
shipping version, so 9.3,
and then set your
deployment target
to one version back, maybe 8.4.
But don't go to 8.3 or 8.2
anymore because then you
But don't go to 8.3 or 8.2
anymore because then you
and your customers don't
benefit from the improvements
that we've implemented under
the hood in that 8.4 release.
When we come out with iOS X
in the fall for the public,
set your deployment
target to 9.3.
Next, Issue Navigator.
Resolve those issues.
Take a look at them
and fix them.
When we tell you that
there's, when we tell you
that there is a deprecated API,
we deprecate API for a variety
of reasons, including to
achieve better error handling
or to better, have
better reporting
or to permit more performance
or just add flexibility
in the arguments return values.
And there's really no excuse
for not moving on to the new API
because we tell you right there.
It tells you what to use.
So, just use that.
Switch over those.
Next, you might decide that you
want to treat warnings as errors
and we've had that for a
while with Objective-C.
But now we also have it
in Xcode 8 for Swift.
But now we also have it
in Xcode 8 for Swift.
I know.
[ Applause ]
I think I'm the first
person to tell you that.
I really like this idea.
I think it's fantastic,
treating warnings as errors,
because it forces you and your
team to address the issues.
It's far too easy to
ignore those yellow warnings
and think you'll come back to
them later and then you don't
and that's the whole
technical debt thing.
Also, do you think this would
work if you pitched maybe a 1.0
of a new project, a new
app, and you said your team,
we're going to ship
1.0, but we're not going
to have any art work in
it, it's not ready yet.
We're not going to
have any icons in it.
We'll ship it and
we'll get those caught
up in the .1 release.
That would never fly.
No one's going to do that,
because this is how users
interact with your app.
Well, actually it's how
many users but not all
of them interact with your app.
Many of them interact with your
app using the accessibility
features that we have built
into the operating systems.
So, why would ship your app with
artwork for people that need it
or want it or use it but then
not have the accessibility
features in there?
That's not fair.
So, resolve some of
the technical debt
So, resolve some of
the technical debt
that comes to accessibility.
Add support for that.
We think that the accessibility
support is as much a part
of your user interface
as the artwork is.
It's built into Xcode,
so you can use Interface
Builder for that.
It's also easy to
do programmatically.
We have a lot of
locale-aware API.
You should be using those
and that's less code
that you have to write.
That generally isn't
new, though.
But these are.
Dimensions and measurement
formatting.
If you've got recipe
apps or fitness apps
and you've been converting
between metric and imperial
on your own code,
get rid of that code
and use our code that's now
available in the fall release.
We'd like you to support
Peek, Pop and Quick actions.
Right? You know, if you
have iPhone 6S right now,
you're probably accustomed
to let's push hard on this
and see if it does anything.
No, nothing.
So, let's push hard on that
and see if it does anything.
Well, that one does something.
It's hard to discover.
How awesome would
it be if every app
How awesome would
it be if every app
that we had already
had support for Peek,
Pop and Push and the 3-D touch?
Next. We want you to run
the Swift migrator using the
developer preview of Xcode 8.
If it doesn't migrate your code,
file a bug report and tell us.
Then we have an opportunity
to fix that so
that when you run migrator
for real in the fall
on the final release of
Xcode 8, it'll likely work.
If it doesn't work,
we resolve some
of our own technical
debt with our API.
The public interface is the same
but the implementation might
change between releases.
And it could be that the way
you use whatever API is a way
that we didn't expect.
So, you have an edge case.
So, tell us about that too.
This is why we do
these preview releases.
We want you to file bug reports.
The report isn't just
banter in the hallway.
And it's not just
writing on a dev forum
and is not just sending
an email to Apple.
and is not just sending
an email to Apple.
The proper way to file
a bug report is this.
BugReport.Apple.com.
Fill in the blanks.
And then once you do
that, you get a number
and then that's the
number that you go
and post back into
the dev forums.
There's a lot of Apple engineers
that read the dev forums.
We like to hear what you are
saying but when you file,
or when you report an
issue in those groups
and you don't include the bug
report number, it's difficult
for us internally to
kind of follow through
and get traction on it.
So, do that.
Next, you're probably
not a great fan
of filing bug reports with us.
Because you've filed
them and then you wait
and nothing seems to happen.
You get nothing back.
In the words of Whitney Houston,
where lonely bug reports go?
Well, they seem to go in
this great big black hole
because you never
get anything back.
Or you think maybe you get
it in front of an engineer
and the engineer kind of
ignores what you're saying.
I want to just assure
you, this is not the case.
One of the first things I did
when I joined Apple
is I did a search
in the bug tracking system,
the issue tracking system,
to find all the issues that I
filed as an external developer.
And a lot of them had traction.
I just didn't have any
feedback from them.
So, I wanted to show you
that if you do file a bug,
we do look at them.
The other thing that I find
is you might spend a lot
of time filing a bug.
A lot of time maybe you're
making some sample code.
You're trying a couple
different devices.
You're checking for regression.
Like, that's great stuff to do.
It takes you maybe half
an hour or maybe an hour,
and then you file
it and it comes back
and it says it's a dupe.
And you're like, oh, I
just wasted half an hour,
hour my life for something
that somebody else already did.
So, I just want to
briefly talk about dupes.
Because dupes first of all
are not a voting system.
It's not like if you copy
somebody else's bug verbatim
and you file a new bug with
exactly the same thing and it,
we're going to say oh,
there's another vote for that,
we should fix that first.
It's not quite like that.
What we do do with them though,
even though they're a dupe,
What we do do with them though,
even though they're a dupe,
it just means these
two are related.
We need dupes too, not
for voting purposes
but because we can have five
people file the same root bug,
same root issue.
The first four don't give
us enough information
to be able to find it.
But maybe it's your report,
maybe it's your fifth one which,
albeit, is a dupe, but
has the information in it
that we need to find the issue.
In fact, an Apple engineer
that's been with the company
for gosh, a couple decades,
made a quip a couple weeks ago.
Paul had said that each bug
report as its host link.
All right.
So, in summary, things
to get going today.
Fix your warnings.
Replace your deprecated API.
Localize your App if
it hasn't already.
Use accessibility.
Or support accessibility rather.
Get Peek and Pop in there.
And then take a look at
the next release of Xcode
and give us some
feedback on that.
With that, let's move
onto Asset Catalogs.
With that, let's move
onto Asset Catalogs.
It's time to move
onto Asset Catalogs.
For you. So, if you still have
files in your File Navigator
like this, go ahead and get them
into an Asset Catalog like that.
The approach is you add a
catalog from the File menu.
By the way, you don't have
to add just one catalog.
You can have as many catalogs
as you like in the project.
Maybe you're working on an app
and that app is a card game.
So, you have a catalog for
the front images of the cards
and a second catalog for the
back images of the cards.
We can do that.
Another example, you might have
your graphic designer download
Xcode for free from
the App Store
and create the Asset
Catalog for you.
And then send it to you or
check it into a code repository.
We could do that too.
When we copy files into an Asset
Catalog, they are exactly that.
They are copies.
We don't reference the
original location ever.
So, they do participate
in version control.
To migrate your project,
you tap the big plus button.
Choose Import From Project.
We're going to give you
a list of all the Assets
that are eligible to be
migrated from the File Navigator
into the Asset Catalog.
There you go.
You migrated your image Assets.
If you previously used
to use the bundle API,
pathForResource etc.,
that doesn't work anymore
because once we compile the app,
the images aren't
free-floating around anymore.
So you won't find anything.
But if you're using image named,
then we'll find them if they're
in an Asset Catalog
and we'll find them
if they're just free-floating
in your File Navigator still.
This API has been
around for a while.
This API Image Name has
a lot of advantages above
and beyond just being
able to find content
from an image catalog.
Asset Catalog.
For example, it internally
caches the first time
that you asked for
an image by name.
We load it up, we give
you back a reference.
The second time you ask
for the same image by name,
The second time you ask
for the same image by name,
we just return another
reference to the same thing.
That's not how the
contents of file API works.
Contents of file loads
new images every time.
So, it's much more perform an,
especially when you're scrolling
through a table,
to use image names.
We support multiple
representations of an asset.
So, with image names, you'd
give it a name, the API name.
You'd let the framework
consider the device
that you're running on.
Consider the resolution of the
display, retina, non-retina,
retina on a Plus device.
And possibly other
differentiating factors
for the media assets such as the
amount of memory in the device
or the version of Metal that
is supported in the device.
And you get an image back.
There's two broad kinds
of asset types for images
that you can consider.
We have scaled images.
Those are like PNG's, JPEG's.
And then we have
single vector images
or just vector-based
images, like PDFs or SPG's.
or just vector-based
images, like PDFs or SPG's.
We treat them a little
bit differently.
On an asset by asset basis,
you can say this asset's going
to be vector-based and that
asset's going to be scale.
You do that by specifying
the scale factor.
So, I'm going to talk first
about some of the scaled images
and then move onto the
vector-based images.
For scaled images, in this
example we're asking you
to provide three different
renderings of the artwork
from 1X devices,
non-retina, 2X and 3X.
If we don't find, because
you didn't include it,
the 2X and 3X, we'll take the 1X
image and we'll scale it up so
that it becomes, well,
an image that's used
on the higher end devices or
the higher density devices.
Likewise, if you just
provided us with 3X artwork,
we'd scale it down at runtime.
These two scenarios
aren't that great.
In this scenario, if I take
the 1X image and I scale it
up for an iPhone 6S Plus, it's
going to look really jaggy.
up for an iPhone 6S Plus, it's
going to look really jaggy.
It's going to have a visual
artifact called aliasing.
It's not very desirable
and the, well,
your customers aren't
going to enjoy it.
This one, at first
glance you might think oh,
I'll just provide the 3X artwork
and let you scale it down.
But there's a huge problem
with that because to scale
down a 3X image, we
have to open a 3X image.
And it's really big.
And then we take an
extraction of the pixels
and create a scaled-down
version for it.
It's an order, two orders of
magnitude, possibly larger.
So, consider this.
You're on a device
like a 5S, 5C.
There's no need for
3X images on it
but you only provide 3X images.
So, we start off with the
baseline of memory in use.
That's fine, but then we
have to load up the 3X image,
down convert it, get
rid of the 3X image
and keep this scaled-down
version of it,
which just temporarily
creates a memory spike.
And if you're good, it's
probably going to be fine.
But if you good, I mean
if you're lucky it's
going to be fine.
if you're lucky it's
going to be fine.
But let's say you're
scrolling at a table view
and as you're scrolling,
we have to do this a lot.
All of a sudden the
memory utilization
for your app balloons
and then what happens
when you use too much memory?
Anybody know, just
say it out loud.
Yeah, right.
We terminate it.
It's terminated because you
didn't provide the artwork.
So, provide the artwork.
In fact, you can do this
really easily with the task or,
not a task but with
an Automator workflow.
You give it a 3X image, let it
scale it down, give it a name.
Scale it down, give it a name.
Great, throw those all
into your Asset Catalog.
And if you wanted to, you could,
and this is another
best practice.
Use this naming convention,
the non-retina ones is
just a line justify.PNG.
And then add 2X and
add 3X the other two.
And then when you drag
and drop the three of them
into an Asset Catalog, we
detect a naming convention.
We create one asset with the
three different representations
as opposed to three
separate assets.
For Vector Assets,
Vector Assets are amazing
because the file contains a
set of instructions on how
to draw the image as opposed
to having it pre-rasturized.
to draw the image as opposed
to having it pre-rasturized.
This is the same image, not
three different versions of it.
Same image scaled
to different sizes.
When you specify
that you're going
to use single vector scaling,
you're providing one
vector-based image.
And at build time,
we rasterize it
into the different
sizes that we need.
It's much simpler for you.
This is the kind of thing you'd
likely do for toolbar images
and navigation bar images.
There you go, scale
factor single vector.
It's also possible
to combine both.
You can set the scale factor
to be vector and scales.
And what you do is you provide
us a vector-based image,
like the limits in
the well called All.
Then, if you want
to do any over-rides
for the other scale factors,
you just provide those
as either other vector images
or PNG's, JPEG scaled images.
Then when we build it, if we see
that you're missing some assets,
we'll just rasterize those
based on the vector image that's
in the All truck well or target.
Otherwise, we'll use the
scaled ones that are provided.
New in Xcode 8, you can
adjust the compression.
Come on, you.
You can adjust the compression.
So, we can say for a
JPEG image you want
to use glossy compression
but maybe
for a PNG we don't want
any compression all
because it's going to be
an item in the toolbar.
We don't want to see
any artifacts with that.
Another issue you can resolve
by using Asset Catalogs,
just in case the pitch
isn't strong enough yet,
is to fix the issue or
resolve some issues.
We're referring to
rounded corners.
The issue with rounded
corners is we have adaptive UI.
So, your button might
contain a text label
that fits perfectly well
until the app is run
in a different language and
then it changes the size.
And when we change the size
of the button, we still want
to preserve the beautiful
rounded corners on it.
The way you would even
get a rounded button
in the first place is
in Interface Builder
you'd select a button
in Interface Builder
you'd select a button
and specify a background image.
And then we apply that
as the background.
In this example, I have an
asset called rounded rectangle
and I apply that as my
background rectangle
but you can see in the
two sizes of the button,
when it's stretched out it's
really horrible looking.
So, one way you can
fix this is the way
that you've been
fixing it all along
which is using Stretchable
Image.
And you say well, I want
to preserve X number
of pixels on both sides.
And that's fine but
one of the themes
of this presentation is
having you write less code
and rely more on the frameworks
and the tools that we provide.
So, instead this is built
into the Asset Editor.
It's called Asset Slicer.
And you can use it to
specify that, the portions
in red, don't stretch these.
Don't distort them.
The portion that's illuminated,
repeat these pixels.
And by doing that, you get
perfect rounded corners
and you don't have to
do any code for it.
This is also something you could
have your graphic designer do
because it's part
of an Asset Catalog.
All right, next up, let's talk
about a design pattern
called Dependency Injection.
Let's first of all talk about
what we're kind of fixing
or trying to change
by introducing this.
So, we have UITextField and
it works with the delegate
and the delegate is called
UITextField delegate.
Fine. And in it, it
contains methods that relate
to text fields, like
textFieldShouldBeginEditing.
Okay? We have WCSession.
And WCSession delegate.
What's inside the delegate?
Methods that relate
to WCSession.
You can see the pattern here.
Which we break with this one.
We have the app delegate
and of course it has methods
that relate to the
application object.
But then we stick other stuff
in there too like databases
and essentially eventually
you have everything
in there including the
kitchen sink just piling up.
And we do it because it's
really easy to reach back
through the Application
object, get the shared object,
cast it and retrieve it.
But it's such a strong coupling
between your view controllers
But it's such a strong coupling
between your view controllers
and your app delegate and your
app delegate doesn't really need
to be the place where that goes.
Instead of a pattern like this
where each view controller
reaches back
to some common object,
maybe that you're storing
in your app delegate,
you could switch it.
Using Dependency Injection,
you take the model object
that one view controller
has and you pass it forward
to the next view
controller at the time
that view controller
is presented.
The idea is you give the
view control everything
that it needs to do its job.
So, for mail, you'd have
a list of mailboxes.
A view controller
that shows a list
of mailboxes would have a model
object representing an array
of mailboxes.
You tap on one of the mailboxes.
Another view controller's
going to present
to show the messages
in that mailbox.
The middle one.
And you pass forward the one
mailbox and it shows those
and you keep passing it forward.
The way you would do that in
a segue is to override prepare
for segue and pass
it for repair.
The way you would do it
if you were programmatically
presenting is in the action
for the button viewed
in instantiate.
The view controller,
pass model object there.
The benefit of this technique
is your view controllers are
standalone now.
They don't have these strong
ties and dependencies.
You can reuse them more.
Coming back, you've
got some choices.
You can do what we do, which
is often to write a protocol
and have you implement it
so that there's a call back
to say the view controller's
dismissed
and maybe update
your model there.
You can pass in a closure.
You can pass object
models by reference.
Or, you can, if you're
using online segues,
it's exactly the same as
overwriting prepare for segue
because it happens in both ways,
forward directions
and back directions.
Another reason why
we like this is
because view controllers are
pretty much like Lego blocks.
They should be able to be
rearranged independently
of each other to
create new structures.
In this case, an iPhone SE's
overall user experience is going
In this case, an iPhone SE's
overall user experience is going
to be different for your
app than it would be
on an iPad 12 inch,
iPadPro 12 inch.
If your view controllers
are independent,
it's easy to do that.
All right.
Now, last year at WWDC,
I gave a presentation
on topics including playgrounds
and modernizing the UI.
And interoperability with
Objective-C and Swift.
And since then, we've added
things to the playgrounds,
things that we couldn't
do last year.
So, I want to show you
some of those things.
With that, we're going
to move to a demo.
So, this is the periodic
table of elements app
that I showed you last year.
Since then, it's been
updated a little bit.
For example, the colors
have changed a bit.
Instead of using states
of matter, gas, liquid,
now it's the kind of object
like a transition metal, metal,
halogen, that kind of thing.
We've also added
support to render it
out so it actually looks like
a periodic table of elements
out so it actually looks like
a periodic table of elements
and that's a collection
view doing that.
I want to show you
some of the code.
One of the things that
changed with this code base
since the last time
that you saw it is
that the data model has
moved over to Swift.
So now I have a class the
represents an atomic element
like nitrogen or oxygen.
And I have a class that
represents a collection
of those called, excuse
me, periodic elements.
This class instantiates
the elements,
the individual atomic elements,
by reading in a property list.
Which I've also stored
in my app here.
But now that I've moved
the data model to Swift,
I can show you the data
model in a playground.
Last year when I did
this, I'm just going
to make a new playground first.
New file, playground.
Last year when I did
this, I was copying,
Last year when I did
this, I was copying,
pasting between my
code and my playground.
And when you do this a lot, your
playground can become really big
with a lot of code in it.
So, instead our playgrounds
now have subfolders
for source code and resources.
I can take my model
objects and put them
into the sources folder.
And then we compile
them behind the scenes
and we implicitly import
all of their public symbols
into the playground to make
them available for you.
Which means if I take this
resource file, my property list,
and include that in
the resources folder
which makes it accessible
to the playground,
I can come over to
the playground here
and instantiate an instance
of the atomic elements.
Here's Californium.
Like that.
So, the ability to
take these source files
So, the ability to
take these source files
and have them automatically
imported into your project
when they're in the
sources folder
or the resources folder is a
pretty, I think powerful way
to keep your playgrounds
themselves small
and concise while also having
more content inside of them.
Now, above and beyond that,
something else happened
since last year that affects
this app in particular.
The International Union of Pure
and Applied Chemistry
confirmed the discovery
of 4 additional elements.
So, now all of a sudden
this Property List file
that I've got embedded
inside my app doesn't seem
like such good idea anymore.
So, I thought well,
we can fix that.
We'll just put it online.
So I set up a little Web
server and put it a JSON file
at this time with
all the elements.
And then the idea is that
when my app launches,
initially it'll use the
embedded built-in data file.
That way if there's no
network connectivity,
there's still something
for the customer to see.
there's still something
for the customer to see.
And this is also a pattern
we recommend that you do.
Then we'll do a background
check,
and in the background
we'll check to see
if there's an update
to the file.
And if so, we'll put
it in the caches folder
and we'll reference
that inside the app.
So, I want to do the network
request in the playground.
And for that, we have the class
formerly known as NSURL Session
and now known as URL Session.
Which is shown here.
We grabbed the Session and the
thing I like about the Session
when I call it out on line 24,
is I give it a completion
handler.
Because this runs asynchronously
in the background.
Go to the Network Request,
let my code continue to run.
When the request either times
out or the data comes in,
it gives us call back.
And in the call back on line 28,
you can see I'm printing
out one element here.
But you actually don't
see it over there.
But you actually don't
see it over there.
That's a problem.
So, just think about
what's happening here.
We have a playground
that's running.
We asked it to do a
background operation.
At some indeterminate
time in the future,
we get a call back saying
this is what we want to do.
But playgrounds typically
execute like a script.
The first line all the way
through to the end
and they stop.
Key word being typically.
But they don't have to.
We can get a runloop and
have asynchronous operations
in our playgrounds.
To do that we import
a new module called
playground support.
And then you ask the playground
for indefinite execution.
And then it never stops,
it just keeps processing.
So, now if I scroll
down to this section,
you can see I'm getting
my callback.
There's cadmium.
All right.
Next I want to expand
on last year.
Next I want to expand
on last year.
Last I showed a drawing,
a rounded corner
core graphics image.
This time I don't just want to
draw an image and preview it.
I want to do a whole table view
controller in the playground.
And we have some new features
in the playgrounds
that let us do this.
Let me just open up
some space in my app.
Call it View.
So, I'm going to make a subclass
of UI Table View Controller.
This is all that it
is, a selected area.
I'm implementing the 2
methods at every Table View
or Table View Controller
are required to have.
Number of objects, sorry,
rather number of items,
self-wrote index that and
returnings themselves.
And I'd like to see that live.
So, this time what we do is we
instantiate the view controller
and then using that
playground support module
that I've already imported, the
one that's right here on line 4,
I grab the playground's
Live View.
And then we take that
view and we render it
into the assistant editor who's
no longer an Assistant Editor
but rather our Live View.
See? It's a Live Table View.
It scrolls, it's active.
[ Applause ]
Thank you.
Is not just a static image.
It's a real interactive
table view.
If you wanted to try some
of our new delegate methods
or even the existent delegate
methods, you could throw them
into the playground and
now interact with them.
No need to put this into
the simulator anymore.
So, now I want to take the two
things and put them together.
Specifically, I have this
background network request
that's happening.
And after I retrieve the data,
I want to reload my table view.
And after I retrieve the data,
I want to reload my table view.
So, let me show you that.
First of all, comment this.
And just to prove to you that
it's totally loading the data
from that site, I'm
going to change this
so I have an empty
array of elements.
All right.
So, I have an empty
array of elements.
I do the network request.
When the network
request comes back
and it's call back, it's a sign.
The new array of elements
that I just pulled in.
And then we reload
the Table View.
All right.
Is that what you would expect?
It's not what I expected the
first time that I saw that.
Oh, that must be a bug in Xcode.
I'll just go file a bug
report at Apple.com.
But it's actually not.
It's a bug in my code,
believe it or not.
It's a bug in my code and
here's what's happening.
We have this background
operation coming in.
The background operation
has a background operation.
It's not on the main thread.
UI is in the main thread.
So, in my closure, the
completion handler,
I can't be updating the
main thread from there,
which is what I'm trying to do
when I reload my Table View.
When I tap on the cells,
we are invalidating them
and that's why they do refresh
and you can see them
at that time.
This is also something
we can fix.
We have something new in
Swift 3, which is a Swift API
for Grand Central Dispatch.
So, instead of that
C API we had before,
I can now say a dispatch
cue, which cues the main cue.
What kind of operation?
An asynchronous one.
We don't need that anymore.
And here's what I wanted
to do on the main thread.
Now it bounces back to the
main thread and it's there.
Now it bounces back to the
main thread and it's there.
Dispatch cue, thank you,
dispatch cue in Swift,
Live Views in Swift and
indefinite execution.
Let's switch back to the slides.
[ Applause ]
Thank you.
So, just as a point of
summary, there's the key points
from the previous presentation,
or the preset demonstration.
Some other tips.
When I dragged those files
into the sources folder
or the resources
folder, they are copied.
They are not referenced.
Also, only methods that are
marked as public, methods,
properties, and datatypes,
etc that are marked
as public are going
to be available
to you in the playground.
So, you might have to go
add some public specifiers
because the default
visibility specifier
in Swift is internal,
not public.
I mentioned using
a caches folder.
Now, we still have
some devices out there
that are constrained
storage wise.
that are constrained
storage wise.
And those customers try
to updates to new versions
of the operating
system and they find
out there's not enough space.
So, what we do when that
happens, when the device is
under storage pressure, is we
go through the caches folders
and we delete everything
we can find
in all the applications
caches folders.
This way we free up space.
We need your help with this.
If you are temporarily
downloading data
and you're not putting
into caches folder,
put it in the caches folder.
Next. I thought it'd
be really neat to take,
it's doing that again.
To take the view controllers
that use dependency injection
and rearrange them in a way that
might suit a different platform.
So, I'm going switch
back to the demo.
Turn on my Bluetooth.
And take the view controllers
as is over the tvOS.
Well, there we go.
I have paired my
Siri remote to my Mac
so I can use it with
the simulator.
It's exactly the same code
from before, same view,
same table view, all
that stuff is there.
I can go over and I can see
the periodic table like this.
And I get that neat TV effect
when I slide over the cells
and its collection view.
It's the same layout code.
It's the same view controller.
It's all the same as
what I had before.
Well, almost.
I added this line
of code so that
when I selected a
collection view cell,
you would get that focused item.
And I used the OS
Compiler directive
to say this is only for tvOS.
Other than that,
it's the same code.
Which kind of brings
me to another point
that if you ever think you are
taking an app from one platform
and just dropping it
on another platform
with no real other changes,
you're possibly doing something
wrong and might want to check
out the human interface
guidelines just
to see how you can make
that platform and that app
on that platform more native and
feel more like it belongs there.
Let me give you an example.
Let's say that you made
an app that does some sort
of like cloud-based accounting.
And maybe you have an iPad
version and on the iPad version,
people fill out invoices.
Makes sense.
It makes no sense,
in my opinion,
to fill out invoices
on a 60-inch TV.
You just wouldn't do it.
Why would you do that?
This is not an app you
would just take as is
and launch it on tvOS.
But, the iPad version of your
app probably has some great
But, the iPad version of your
app probably has some great
visualization about how
the company is performing.
Maybe you've got some
graphs or charts.
Those would be awesome on a TV.
You could have a version of your
app that has a Live Status board
of how the company's doing.
And maybe in the company's
boardroom or something it's just
on and it just animates
through and shows an update.
It's the same data model.
It's the same data access.
But you pivoted that
data in a way
that makes it more
applicable for the platform
in which it's running.
And that's an idea I
want you to think about.
How can we take the same data
that we have and just pivot it
in a way that works
for that platform?
In summary, modernizing your
app is an ongoing process.
We want you to rely on the
frameworks as much as you can.
If you can get rid of
code that's in your app
and instead use code that
we've got in our frameworks,
that's code let's code
for you to maintain.
We'd like you to do that.
We want you to get started today
with finding issues with Xcode,
with the Swift converter.
We want you to architect
your app
with fewer inter-object
dependencies so it's easier
with fewer inter-object
dependencies so it's easier
for you to rearrange your app.
Finally, we want you to
consider bringing your app
to other platforms
of ours [laughter]
by pivoting your data model.
There are some related
sessions you can check out.
There you go.
And other than that, you
can check out our link
for this particular session.
And that is it for me.
Thanks, everyone.
[ Applause ]