Transcript
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[ Silence ]
>> Good morning.
[applause] Before
we get started,
I'd like to do a
small, informal survey.
How many of you are
new Apple developers?
Please clap your hands.
[applause] Excellent.
Welcome. And how many
of you have made an app
for iPhone, iPad, or iPod Touch?
Please clap your hands.
[applause] It sounds
like about all of you.
OK. And how many of those
that have made apps have
brought those same apps
over to OS X, to the Mac?
[applause] Sounds
like a few of you.
But it sounds like we're all
in the right place today.
Did you know that in
the last quarter alone,
Apple sold nearly
4 million Macs?
Yeah, and we want your apps to
be in every single one of them.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And we're here to show
you how to do that.
Now, after you leave
here today, you're going
to be ready to do three things.
Number one, number one, yeah,
that's all right, you're going
to be able to rethink
your iOS app in terms
of a Mac, in terms of OS X.
Two, you're going
to be able to--
you're going to be ready
to restructure your code,
just cleanly separate
your model from your view
and your controller so that you
can maximize your code reuse.
And number 3 is easy.
You're going to be ready
to just get started.
So let's talk about your design.
Many of you may be thinking,
"OK, so I have my iOS app
and I'm going to bring it
over to OS X and I'm going
to leave everything the same
because that's going
to be pretty easy."
I'm going to discourage
you from doing that.
Your users are going to love
it if you embrace the things
that make the Mac great.
So what makes the Mac
different form iOS?
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Well, for one thing,
screen size.
If you think about it, your
iPhone is on a 4-inch display
if you have an iPhone 5,
or if you have an iPad,
it's on a 10-inch display.
But our Macs go from
an 11-inch Macbook Air
to a 27-inch Thunderbolt
Display.
And your users could
have multiple displays.
So, that's something
to think about.
And then on top of that,
your content is going to be
on a window that's resizable.
So, who knows how big your
content will be for the user
at any one point in time.
So, I'm going to encourage
you to use Auto Layout
because that's going to
solve a lot of your issues
with these different
display sizes.
OK. Let's talk about
input devices.
On iOS, your primary input
device is your finger
and as such, we've given
you guidance to use controls
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and buttons that are
44 points by 44 points.
Now, in OS X, your input
devices are a trackpad or mouse,
and are much more precise.
So you don't want to make your
controls unnecessarily large
on OS X.
It's going to look-- well,
it looks out of place
so keep that in mind.
What about other things?
What are some other things
that make the Mac different?
Well, for one thing, the Mac's
got menus and keyboard shortcuts
and these aren't just any menus.
Mac users are going to
be expecting to see File,
Edit, and the Window menu.
And they're going
to be able to--
they're expecting to see the
standard keyboard shortcuts
for those menus.
Like for instance,
Cut, Copy, and Paste.
And they're going to expect
to see Undo and Redo support.
You may have it in your
iOS apps but you may not.
But on the Mac, if
it's appropriate,
please use that because your
Mac users will expect it.
They're going to expect to be
able to drag files and texts
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and images into, out of, and
between windows in your apps.
Quick Look is a technology
on OS X that allows users
to see the contents of your file
without opening it in your app.
And we've handled many
of the common cases
like for PDF, and texts, images.
But if you're using
a custom file format,
if you're making a custom
file format in your app,
it'll be great if you added a
Quick Look plugin to allow users
to see the contents of your
file without opening your app.
That would really
make them happy.
Similarly, Spotlight, that's
the technology that allows users
to search the contents
of your file.
So if you have a
custom file format,
consider making a
custom Spotlight indexer
so that users can search
the contents of your file.
So then, we've talked
about design a little bit.
Let's talk about your code.
Now the good news is that
you can leverage a lot
of existing knowledge that
you already know from iOS.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
For instance, the
design patterns,
the Model-View-Controller,
the Target-Action pattern,
the Responder Chain Delegation,
all of those patterns work
on iOS just like
they do in OS X.
A new development
environment, Xcode,
with its built-in user Interface
Editor and Static Analyzer,
its profiling tools,
and all the things
like the source control tools
that you get from Xcode,
all of those are available
on OS X as well as an iOS
because you're using the
same development tool, Xcode.
The languages, C, Objective-C,
C++, and many of the frameworks
like Core Foundation
and Foundation are going
to be the same on iOS
as they are in OS X.
The resources, your images,
some of your images might be
different because you're going
to be resizing them to
make them smaller perhaps,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
but some of them
will be the same.
You'll be able to
use those again.
And then, also the
image technologies,
this week we're talking about
asset catalogues, Xcode,
the Xcode talked about
that and that's one
of the things that's
available on both OS X and iOS
and you can use that for this,
and also the naming conventions.
If you're doing a Retna Mac,
you're going to add at 2X
to your file names just
like you do on iOS.
And localizations,
a lot of your--
most of your strings are
going to be exactly the same
and the technologies used
to localize are going
to be the same.
So you're going to use NS
localized string method
to make sure that your
localizations work.
So, I've outlined some of
the things that are the same.
So what's different?
Well, let's take a deeper
look at the technology stack.
So here's a big table
and that has a lot
of the frameworks
on iOS and OS X.
There's a couple of things
I'd like you to notice.
Number one is that a
lot of the frameworks
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
on iOS are the exact
same as they are in OS X.
And this is actually just
a small subset of all
of the frameworks that
we have available.
I only did one slide here.
Actually, I did two.
We'll look at the other one
in a second, but, anyway.
The-- but yeah, so keep in mind
that most of the frameworks--
a lot of the frameworks
are going to be the same.
Now, there are some that are
different and of the ones
that are different,
most of the ones
that are different are going to
be subsets of the OS X version.
So you get to keep your code
the same because you're going
to be using the subset
part on iOS.
So when you move to OS X, you
can even use some new features.
The last thing I would like to
point out, most of you are going
to be spending a lot of time
in UIKit and the news is
that UIKit does not
exist on OS X.
But the good news is
that we have AppKit.
And actually, UIKit
was inspired by AppKit.
That's right.
That means that a lot of the
things will feel very familiar.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And we're going to talk about
some of the differences and ways
that you can cope with those.
And then one more slide on
technology, I want to talk
about games briefly
because some of you--
many of you may be making games.
If you're making games
for OS X, the good--
there's some great news.
One thing is we have OpenGL,
Game Center, and SpriteKit.
And if you're making a Mac 2D
game, really take advantage
of SpriteKit if you can
because that's going to do most
of the heavy lifting for you.
That's already cross-platform
and so you'll have an
app that works on both.
So, now that we've talked
a little bit about that,
let's go into design patterns.
Someone recognize that,
that's the Model-View-Controller
design pattern,
and hopefully you're
using that in your apps.
If you're not,
Model-View-Controller is a
software architecture pattern
that separates the
representation of information
from the user's interaction
with it.
And the model, we're
going to talk about first,
is only supposed to be used
for your data structures,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
your business rules and logic.
And if you cleanly
separate it out that way,
you're going to get
some benefits.
Almost all of your model
code is going to be reusable.
Why? Because the frameworks
underneath the model
are cross-platform.
So what that means,
if you have some code
and here's some iOS code,
that's-- it's going to--
in it an array, a beautiful
array with ten elements
and we're going to add a string
to it, in this case, WWDC 2013.
Your OS X code is going
to look like this.
It's the same, right?
That's great.
So you don't have to
do any work there.
So cleanly separate your model.
Now, one thing to
keep in mind is
that your model code may be
making an assumption that's not
true on the Mac which is
Macs are 64 bit and iOS,
your iOS code may not
be ready to handle that.
So how do you-- what
do you for that?
Well, it's really easy.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Adapt NSInteger and NSUInterger.
Those are variably sized
integers that are going
to give you 64 bit
on the hardware
and we'll give you 32
bits when you need it.
So, that's perfect.
Now what if you really do need
a 32 bit integer and not 64 bit?
Like for instance,
if you're doing
about binary file format that's
already specified and you want
to make sure that it is
right, well, we recommend
that you use uint
32 t and its cousins
and that's got you
taken care of.
So what about platform
specific code?
So if I'm writing iOS only code
and there may be some times
that you do that, you're going
to use the preprocessor
macro #if TARGET OS IPHONE.
And if you're doing
Mac only code,
you would use #if TARGET OS
MAC and not TARGET OS IPHONE.
OK. So now that we've
talked about the model,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
let's go on to the view.
The view is any output
representation of your data
and it's also where you're
user interface lives.
So, a big part of the user
interface are the built-in
control set.
So what does it look
like on OS X?
Well here's kind of an
idea of the landscape.
We have a lot of controls
on iOS a ton of controls,
even more controls on OS X.
And they overlap and there are
a lot of controls in common
but there are some
that are different.
So, you'll need to
look at alternatives
in some cases between the two.
One of the most used controls
on iOS is the TableView,
and good news, there's
a TableView on OS X.
So, it's called NSTableView.
If you're noticing a pattern,
it's just a coincidence
but all the UIs and
actually, yeah.
So, there's some
similarities between the two.
They both use data
sources as their delegates.
They both encourage the use
of reusable cells that's going
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to maximize your performance.
And they both animate insertion,
deletion, and moving of cells.
So, that's great.
There are some differences too.
One of the things
that's different is
that NSTableView actually
has two different variants,
that's for legacy reasons.
You want to use the
view-based variant.
That's most similar to iOS.
The other one NSCell and
I'm done talking about that.
It's an NScell-based
variant but don't use that.
OK. The other thing to keep
in mind is that you're going
to get multiple columns.
So, yay, that's cool.
And lastly, is this really
the right control for you?
It may be.
If you're doing tabular data
then it's the right control
for iOS and OS X.
But if you're doing
something else,
then it might be the
right control for iOS
but maybe not for OS X.
So let's take a look
at some examples.
So here on your left, you're
going to see a TableView
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that the user selecting a region
out of a whole list of regions.
In this case, they've
selected United States.
On OS X, the appropriate control
to use here would
be a popup menu.
So, think about that.
Now, one thing about that
is that you can make those
with NSPopupBotton or just drag
them out from Interface Builder.
That's probably the
easier way to go.
So what about something else?
OK. So let's look at this one.
OK. So, here's a TableView
where it has it broken
up into sections.
So this first section, again,
you're selecting an item
out of-- in this
case, just two items.
So, on OS X, we'd recommend
using a radio-button
matrix instead.
And on OS X-- sorry, on
iOS, we have a on-off switch
in your TableView, and
that would be best suited
for a checkbox.
And if-- one thing else
I'd like to point out.
This window here can be
made with a StackView
which will make your
job a lot easier.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So check out that.
NSStackView, it's a new
technology for Mavericks.
OK. So, what if I want
to do a custom view
like making a custom button
or that kind of things?
In a lot of cases,
you're going to want
to overwrite UIView or NSView.
So, what if-- so
what's the differences?
While they both receive
and handle events,
they're both responsible for
drawing, but there's a couple
of differences so
let's go in those.
The UIView's origin
is in the upper left
and the NSView's origin
is in the lower left.
Before you despair, we'll have
some information on how to fix
that or accommodate for that.
The UIView always has a layer, a
Core Animation layer backing it,
and that has some
interesting benefits.
On NSView, you can have
a Core Animation layer
but you have to opt-in to that.
And then, subviews can draw
outside their bounds on UIView
but they're clip to
their bounds for NSView.
So let's talk about origins.
I promised to show
you how to do that.
Here's what it looks like.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
In UIView, you've got your upper
left origin, NSView, lower left,
you're just going to overwrite
isFlipped and return yes.
And what does that give you?
Well, that.
So, there are some controls
that are actually already have
the origin flipped for you
in advance, so be aware, and
they are NSButton, NSScrollView,
NSSPlitView, NSTabView,
and NSTableView.
So, what about layer
backed views?
So we have the Core
Animation layers on UIView.
What are the benefits?
Why would we want to opt-in?
Well, we'd get smoother
animation.
And if you want to do
anything with CAFilters,
then that's the right
choice for you.
CAFfilters are pretty cool
and if you watched
the SpriteKit Talk,
then you know a little
bit about that.
The downsides are that
there a lot more--
they can be more
resource extensive.
So, we urge you to test.
Try it out, see if it works
better, see if it fits
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in within the resources you
want to use, and then pick one.
So what about layer
backed views?
I had-- sorry.
So we have layer backed views, I
told you what the benefits are,
and the UIViews are
automatically
and you have to opt-in
on NSViews.
So, how do you opt-in?
Well, in code, you would
call setWantsLayer, yes.
But you can also do an Xcode.
And so in Xcode, you go into the
Interface Builder portion of it
and you would-- in the inspector
on the right, you're going
to pick the last tab, that
one there, and then you click
on the little checkbox
next to your View
and that would make
it layer backed.
OK. So for iOS, your animation
code might look like this.
So it's-- you do an
animateWithDuration,
you pass it a time,
and then you're going
to give it an animation block.
Here we're setting the frame so
we're going to animate the frame
and then I'm closing the block.
On OS X, we're going to
use animation proxies.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The codes look very
familiar but it's going
to be slightly different.
So, instead of changing the
frame on the view directly,
you're going to do
something like this
where you call this
animator proxy in the middle
and that's going to make sure
that your view gets
its frame set
and also that it will animate.
Now, we do also have
some additional--
if you notice here that the--
we're not setting the
time of the animation
that has an implicit duration
and there's some more details
on that that you
can learn about.
And we'll have references
to that at the end.
So, what about events?
So you have on iOS these gesture
recognizers and they're great.
So, you have the
UIGestureRecognizer
and its subclasses and it makes
it really easy to handle events.
On OS X, you can handle all
those same events but we--
there's no such thing as
an NSGestureRecognizer.
So how do you do it?
So here's a
TapGestureRecognizer.
And TapGestureRecognizer,
the idea here it's a lot
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of times you use for
a simple interactions
like a simple touch.
So, on OS X, you'd be-- it
would be a simple click.
And so, you would
overwrite the mouseUp event
and handle your click there.
So, pretty easy, and you
could do mouseDown as well
but we recommend mouseUp because
it's more what the user expects.
So they can cancel the event.
OK. So what about long press?
Well, for long press,
you could do this.
It's kind of complicated but it
all just run through real quick.
You set up a timer and
half a second timer that's
to mimic the way that the
default long press recognizer
set up.
And then you're going
to do something.
You've set up the
selector to do something,
that's the bottom method.
And then in your mouseUp event,
you can invalidate that timer.
So, like for instance that they
mouseUp before the half second
was over then it would stop it.
So, you'd be effectively
doing a long press there.
But 99 percent of the
time, you're going to want
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to use a Right Click instead
because the long press is not
really going to be familiar
with a-- for the OS X crowd,
and so, use the right click.
And you're going to want
to show a menu probably.
So to help you with
that, we have a method
that you can overwrite which is
menuForEvent and that's going
to get called if you
right click on something
or if you control click on it,
any kind of contextual
click, will give you this.
And with this, you're
going to pass back the menu
which is going to
handle the interaction.
So what about dragging?
Well, one thing you
could do is you could set
up the mouseDown
event and you're going
to record your drag start
location and your mouseDragged,
you're going to do-- you're
going to move the view and then
in the mouseUp event
you'd clean up.
And that works really
well especially it will--
I should say that works really
well if you're inside of a View.
So if you're moving
something within a View,
then that works great.
So-- and that's kind of
what you're used to in iOS.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But what if you wanted to do
something really fancy like,
say drag something from
one window to another
or perhaps one application
to another.
How would you do that?
Well, it's pretty simple.
I'll show you how to do it.
So you're going to use this
for mouseDown or mouseDragged
and then you're going
to set up a pasteboard
and in your pasteboard,
you're going
to clear the current pasteboard
and then you're going to pass
in the element that
you want to have--
actually, the model behind
what you want to have dragged.
In this example, we're dragging
an image, so we're going
to just pass in one
element array,
that's the new array syntax-,
and, pass in that image.
And then we're going
to call this bad boy.
drawImage at offset event
pasteboard source slideBack.
OK. So what is all that stuff.
So, first thing is the dragImage
and that's the image
underneath the mouse pointer
as you're dragging.
The second thing you're going
to pass is the location,
the start location.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And the dragOffset
actually is ignored
so let's not talk
about that anymore.
The event is the mouseDown
event that you've been passed in
or mouseDragged event
and only use this
with mouseDown and mouseDragged.
The documentation-- by the
way, if there's anything here
that I'm saying, go look
at the documentations,
it's got all the stuff.
But I'm just pointing you
in the right direction here.
Pasteboard, so the pasteboard
is what you just set up there,
the source is self
and then slideBack.
That's when if the user cancels
than whether it slides back
in the place, cool
animation there.
So, that's-- you can
put yes or no there.
OK. So, now that we've
talked about the view,
let's take a look
at the controller.
Now, the controller is the part
of your Model-View-Controller
system that handles user input.
And it's going to mediate that
input and send it to commands
for the Model or View to handle.
So, what do we do--
what are some tips
for migrating the controller?
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
First off, this is the common
mistake, UIViewController.
There is an NSViewController
but it's probably not
what you're looking for.
You probably want to use
NSWindowController instead
which is a lot more similar
to the UIVIewController.
So, look there if you want that.
And a lot of you may be using
or I would say almost all
of you are using
UINavigationControllers.
There is no such thing as
an NSNavigationController.
And the reason-- let me think
about that for a second.
UINavigationController,
what does it do?
Well, it allows you to
navigate between lots
of different TableViews that are
stacked on top of each other.
And why do we stack them
on top of each other?
Because we have a 4-inch screen.
So, we don't really
need that on OS X.
In any case, it doesn't exist
on OS X so you're going to have
to find some alternative.
But it's not the right
interaction anyway.
So, the next thing that I
will point out is Bindings.
Bindings is going to really help
you out here with controllers
because bindings is a way
on OS X that you can wire
up your user interface
without using any code inside
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of Interface Builder.
So that's pretty cool.
OK. Next, NSDocument,
NSDocument is amazing.
It allows you to do some really
cool stuff and it's going
to really reduce the
amount of controller code
that you have to write.
And you may be thinking,
"NSDocument, that sounds like--
is that similar to UIDocument?"
Well, yes it is.
In fact, they have a
lot of similarities.
Both of them are responsible
for saving and loading,
both of them will give you undo
support very, very cheaply,
and both of them are
your tickets to iCloud.
So if you want to get to
iCloud, adopt UIDocument
or NSDocument or both really.
And-- but there's
some differences
between NSDocument
and UIDocument.
NSDocument has some extras,
some real nice things
that you should take
advantage of.
You'll get for free
really most of them.
One of them is that
you're going to get--
if you set up a document-based
app on OS X, you're going
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to get a File, Edit, and
Windows menu for free
and they're almost entirely work
without any code on your part.
You're going to get open
panels and save sheets.
And, you know, when you quit
your app and you haven't saved,
you get that little
dialogue that comes down,
that's for free, you'll
get that, unless you turn
on auto save and then,
you don't really need it.
But if you turn on auto
save, you get versions.
Yes, you're going to get this
cool UI, a time machine UI right
within your app, that allows
you to compare one version
of your file with another one.
So that's really cool.
And there's a really a lot
more that NSDocument can do.
So, check out the
documentation for NSDocuments.
OK. So, I'm going to
bring Dan Schimpf on stage
and we've been talking a lot
in abstract and he's going
to show you an iOS
app that we're going
to bring to OS X in a second.
So, take it away, Dan.
[applause]
>> Hi, good morning.
OK. I'm going to show you--
I'm first going to start off
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with my awesome iOS application
that I'm working on some
into the store, and it's a
simple graphics application.
And what we can do here is
just tap and make a few shapes.
So, I can also change
what size I want to make
or what shape I'm going to make.
I can drag-- even drag it
around and put that around top
of there, like do
three whole shapes.
You can even change the
color, sure, let's do that.
So now I have a nice little
picture of a house with my--
this is what my house
looks like.
OK. So, that's just a demo.
That's my brand new application
but I'm thinking I want
to bring this application
to OS X.
So, I'm going to open the
project here and let's just go
through some of the code.
So, as you can see I've
already separated my code
out into a Model
View and Controller.
So this is my document model.
Don't need to go through a whole
lot of this right now but it--
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
but the important thing
is that a lot of it--
this is all things that
are cross-platform.
It imports foundation, things
that are on both platforms.
And the view side, I have the
document view itself, the thing,
the canvas, and then I have
the shape view which is--
stand for each of
these individual shapes
that I can drag around.
And then on the controller side,
I have a standard controller
hierarchy, an app delegate,
and then I have adopted
UIDocument because I want
to bring this to iPod and win
an Apple design award next year.
And then I've got a view
controller for the view
that I see and then
two controllers
for the things that pop up.
So, this is all pretty standard.
And now I want to start
on bringing this to OS X.
So what's the first thing I do?
Well, the first thing I'm going
to do is just make a new target.
So I'm going to make
an OS X application,
so the Cocoa application.
I'm going to make
this shape heart OS X.
You don't have to call it--
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
if you don't have the OS X
at the end, I'm just going
to say OS X just so there's
no confusion during this demo.
And I'm also going to make a
document-based application.
So, you can see this is
made a target for me.
And also because I know this is
a heavy graphics application,
I'm also going to
add a framework.
I can search the courts
framework and it knows
that this is an OS X
target so it's going
to only give me the OS
X version of courts.
OK. So now, I have
this basic app
and because I've separated my
model cleanly, I can select all
of the model classes and just
simply add them into my--
excuse me, add them
to my OS X target.
Now, if I switch to my OS X
target, I can actually build
and run and see what it gets me.
So here we have-- this
is what you get for free.
You get a whole-- you have
windows, you can make--
I can make many of them,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I got all of the menu bar
items that actually work.
And I probably don't
want to shift
with my document contents there
but it's a good starting point
that you get for free and then
you can adapt it from there.
So I'm going to hand
it back to Cortis,
he's going to talk
more about that part.
>> Thanks, Dan.
So, awesome.
So we have this app and it
does some really cool things
like your documents here.
But we don't-- we're going
to have-- where's our colors?
Where's our little shapes?
So let's talk about--
we're going to talk about
some migration strategies.
They're going to help you move
over your view and controller
because we've only moved
over the model at this point.
Now keep in mind, this is kind
of a tool box of approaches.
We're going to give you a
bunch of different approaches.
You know your code so you should
decide what's the right approach
for which situation.
And your apps may
use several of these.
And so to help with this, we're
going to talk about it in terms
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of a particular example.
In this case, we're going to
talk about it in terms of color.
Now, on iOS, you may all
be familiar with UIColor.
It's a relatively simple class,
it allows you to create colors
with red, green, blue,
and alpha, and allows you
to set them on the
current context.
Now, it turns out that there's
another class on OS X called,
surprisingly enough,
NSColor, and it allows you
to create a color with red,
green, blue, and alpha and set
in on the current context.
Now, NSColor does
some other cool things
like it will allow you to
set up seem like cake colors
and patterns, color spaces.
But for now, let's just
focus on those two things.
OK. So, if were overwriting
code that we're using UIColor,
I might do something like this.
UIColor redColor, that's going
to make a new color for me,
and then your color,
aColor that set.
So that's going to set
on the current context.
Pretty simple.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
On OS X it might look like this
and the only difference here is
that we have a different class
name in place of the UIColor.
Now, this is what we're going to
call the mirrored code strategy
and for purposes of talking
about it, I don't know
if it's really officially
called that
but we're going to call that.
Now, just to show you a little
bit more what that might look
like in a more complicated case,
let's look at this next one.
This is not with colors.
There's a fair bit of code so
let me explain what it's doing.
It says to create a new
view, it's going to center it
on its parent view
and then it's going
to insert it underneath all of
the other views on that view.
OK. So this first
bit of code is going
to compute the new
origin, the new X and Y.
And we did that with a little
bit of math and it turns
out that the math for OS
X is going to be the same.
So that part of the
code is the same.
And then we're going to
create the view itself.
We'll make the frame, the
CGRect frame, and we're going
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to create it with initWithFrame.
And if you notice, the
OS X code is very similar
but there's a couple of changes.
One is that we're using an
NSRect instead of CGRect,
and we also are using an NSView
instead of a UIView, so--
but very similar at this point.
And then for this last bit,
we're going to insert it
underneath all the other views
on that view.
So this is subview, so
all of the other subviews.
I'm going to use
insertSubview atIndex on iOS.
On OS X, we don't actually
have that API so in that case,
we're going to have
to call addSubview,
positioned, relativeTo.
And so what that does is it--
we're going to add the subview
which is the one that we just
made, and then we're going
to position it with
NSWindowBelow
and that's we below something.
And since we're passing
nil for our relativeTo,
it's going to be
below everything.
So it does the same
thing as the iOS code.
OK. So that's the
mirrored code strategy.
What are some of the benefits?
Well, it's going to give
us a lot of flexibility.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So we're going to
have things on iOS,
we're going to write our
code completely different
on iOS from OS X.
In fact it can give you
something completely different.
So that's kind of cool but
it has some downsides, right?
If there's code duplication
there which means
that whenever we want to change
something on the iOS side,
let' say add a feature
or fix a bug,
it's going to require a
change on the OS X side.
So there's greater maintenance
cost but greater testing cost.
So when do we use this strategy?
Is it ever appropriate?
The answer is yes, it is,
sometimes appropriate.
When you're using heavily
platform dependent code,
when there's stuff that's
really just very different
between the two, then this
might be the right approach.
But there are some other
approaches that we can take.
So let's take a look at those.
One thing that we can do is
that, it turns out that UIKit
and AppKit are actually built
upon a common framework.
And so, we can drop down
to that lower framework.
And it turns out that
that will give us code
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that is cross-platform
out of the box.
Let's look at some code.
Here we're dropping down
to the Core Image framework
and it turns out that Core
Image has a CIColor there
and CIColor has a color
with red, green, blue,
alpha so we can create
a red color.
And in this case, we're
actually going to--
we're not setting on
the current context.
We're creating an image with
that color because that's one
of the things that Core
Image would want to do.
And so, that's the code
there for doing that.
Now, some benefits
to using this--
since lower level
frameworks are cross-platform,
we're going to get-- we're going
to maximize our code reuse.
It's very robust and there's
a lot less maintenance
because we only have one
set of code to deal with
and with the interface
is common so all
of our code calling this
is going to be the same.
There are some downsides.
For one thing, it's going to
require that you rewrite a bunch
of your code and
perhaps most importantly,
and I want to stress
this, you're losing a lot
of functionality by dropping
to the low level framework.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
There's a reason why
we're making NSColor
and UIColor available.
And it's not just to
like duplicate work.
So, because, you know,
and CIColor doesn't
handle color spaces,
it won't do CMYK color,
it won't do patterns.
So, these are all things
that you're going to lose.
If you ever think that
you're going to need that,
then probably not
the right strategy.
So when do you use this?
It's when the lower level
framework provides the needed
functionality that you needed,
for now and in the future.
So look at it and say "Hey,
is this appropriate match?"
And if it's not, then let's
look at some other strategies.
OK. So, from software
engineering, if any of you took
that in college,
you may be familiar
with the adapter pattern.
The idea here is that we
have some common source
and it's already targeting iOS.
And the code is already
written so we don't really have
to do anything on iOS.
But what if we made the OS
X code work the same way?
So we could stick
an adapter in there
and that would give us the same
interface for iOS and OS X.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And let me just modify
this slightly.
We're going to stick--
we're going to make this
a little bit different.
I want to make that
adapter actually
across both iOS and OS X?
So if we do this, it will take
a little bit of extra code
but it means that our iOS
code-- sorry, the iOS framework
and the OS X framework can
change and it doesn't matter
because our code, our adapter
code can stay the same.
And so, the code that's calling
it doesn't need to change.
And so, we can just
change the implementation.
So that's actually
a nice approach.
And it would look
like this in code.
Perhaps, this is
a very simplified,
just the header file
version of it
and without all the interfaces
that you would need
for various things.
But this gives you an idea.
We created class
called XPlatformColor
and we'd base it off of
NSObject, and underneath
that class, we'll place a
UIColor as the underlying color.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And so, whenever we need to
do something on the color,
we'd actually call through
to iOS to do that for us
so we wouldn't have to
duplicate that code.
And on OS X, we could put
this in a separate file.
In this case, we're
putting it in on one slide
so we use the condition--
the cross-platform macros
that we talked about earlier.
But in this case, we're
going to base XPlatformColor
on the underlying
color of NSColor.
So that's what that
would look like.
So what are the benefits
of that?
And so you're going to have to--
by the way, this is doing
some hand waving on the rest
of the interface because you're
going to have things like color
with red, green, blue, alpha
perhaps, or a red color
or whatever you want to
have as your interface.
You can choose, right?
This is your class
that you're making.
So what are the benefits
of that?
Well, one thing, you're
going to be flexible again,
a lot more flexible
than mirrored code.
You're going to maximize
your code reuse.
This is a lot more reuse
than mirrored code.
Why is that?
Because your interface
is the same.
So any place that you need
to color, you're going
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to call XPlatformColor.
And all of your platform
specific stuff is hidden
underneath an implementation
of the XPlatformColor code.
So that's nice.
It's a simplified interface
because you're making it.
It's tailor-made for
you, so that's great.
And it requires less maintenance
because, again, you're--
you have a common interface and
unlike mirrored code where you,
you know, you want to change
something, you had to change
in all different places.
So that's great.
The downsides are, it
has some downsides,
it's a lot of additional
code that you got to write.
So-- and so, there's going to
be another strategy we can talk
about next that has a little
bit less code, so, anyway.
When do you use this?
Well, you use this
when you're dealing
with an underlying API that's
significantly different
between iOS and OS X.
And this is a great
pattern for that.
OK. So, this is a
great strategy.
What about another strategy?
OK. So here's one that we can
take advantage of in some cases
and that is the adapter
pattern using #define.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now, #define is the
pre-processor macro
that in this case is, what
we're going to do is we're going
to substitute every occurrence
of XPlatformColor with UIColor.
And we're doing that before
the compiler ever gets to it.
So this happens before
compile time and that's going
to have some cool
advantages for that.
And for OS X, we would
substitute that with NSColor.
So every time we
see XPlatformColor,
it's an automatically
insert that.
Now, what does that do for us
and what is it not do to us?
There's a couple of things.
For one thing, there's
almost no new code to write.
You saw it there, that's it.
OK. So, that's nice.
It's going to give you
compile time air checking.
So because it's doing it before
the compiler ever gets to it,
it will tell you if you're using
it wrong, the compiler will.
So if you're using a selector
that's not appropriate,
it's going to tell you that.
Now, there's some downsides
and the first one is key.
Everyone pay attention.
This is only for
supported classes.
Let me say that again.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Only for supported classes.
So what are those classes?
UIColor and NSColor, UIFont and
NSFont, UIImage and NSImage,
and UIBezierPath
and NSBezierPath.
If you have a class that is
not in this set of four pairs
and you want to use the
strategy, please don't.
You will have undefined results.
So-- and the other thing to
keep in mind is that even
for these classes, it's
got limited API coverage.
So just because we're doing
this #define it doesn't mean
that we magically
get CMYK on UIColor.
We don't. It doesn't
happen that way.
So-- but the compiler
will warn you if you try
to use it so, that's good.
It will say, "Hey,
you-- this is an error."
So, anyway.
The other thing to
keep in mind is that,
if you're doing cross-platform
work which you obviously are
because you're in this talk
and that's what this is about,
and you're doing
archiving of your things,
it's going to require
some custom archiving.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
because if you archive,
what ultimately ends
up being a UIColor
and you try to bring
that into OS X using
iCloud, that is going to say,
"I don't know UIColor is,"
and it's going to barf on you.
So, you're going to have
to write some custom
archiving code for that.
And that's pretty easy.
What you just want to do is
you want to save it in the way
that both platforms
can recognize.
So, migration testing
is my next slide.
And one thing to keep in mind
is all of the stuff means
that if you're code
compiles, it doesn't mean--
necessarily mean it's correct.
So please test.
Unit tests are good,
very, very good.
You should use them.
Xcode has some cool things in
it, Xcode 5 for doing that.
Manual testing is important too
because there are some things
that you probably can't
cover in a unit test.
Don't forget to send
it to your users.
They have different system
configurations and they're going
to use the software
differently than you.
So, do beta testing.
That's why there's reason why
we have the provisioning profile
so you can send out your
apps to those people.
And testing plans, you know,
if you have a testing plan,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
then it means that every
single time that you come
out with a release and
you follow that plan,
it's going to mean that your
software is a lot more--
well, at least it's
tested, right?
Now, I stress this because the
number one reason why apps get
rejected from the app
store at least initially is
because they crash
during the review process.
So you don't want your app to be
one of those because it's going
to take more time
to get it reviewed.
And that's actually good
news because if it crashes
for the reviewers
then it's not going
to be crashing for your users.
That may even worse if it
didn't-- so do your testing.
Anyway, I'm going to bring Dan
back on stage and he's going
to show you how we've
implemented some
of these strategies to
bring the iOS app to OS X.
Thanks Dan.
[applause]
>> Thank you, Cortis.
I've been hard at work while
Cortis has been talking
and now I have a new final
copy of my application.
So here we are, this
is an untitled document
and you see instead of
the toolbar at the bottom,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I have a toolbar on the
top that has selectors
for the different shapes and
the Stroke and Fill colors.
So-- but the same
things applies.
I click, I can create things.
I can even create a new
document and I can even--
I can use that to make the
same shape that I did before.
I can drag it.
All right, two documents here.
And I can change my Fill color.
Let's do, I'm going to make the
same [inaudible], a nice purple,
it could be different planet.
OK. So then here we have
[laughter] roughly the same
document here.
And I can give this a name, see,
"My House," saved
on the desktop.
So let's say-- OK
and I saved it.
I have made some other
changes by mistake.
Let's say-- oh, and
now I kind of want
to see what, versions
in the past.
So I can use Browser Versions
and then this is entirely
for free just by do-- but
by dotting in this document.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And I can go-- oh, this is
the one I actually wanted us
to save.
Now, this is-- that's
how it works.
OK. So let's go back
and look at the code.
OK. So, I've re-organized
my code a bit.
I have-- I've broken
all the common code out
and take the common source
and I have as different spots
for iOS and the macro source.
So in my common source,
we have all the model bits
and I was [inaudible].
We had already done some--
a little bit of work
that like of--
well of course, I was talking
about what the platform color.
So here we have our platform
color and I can show you,
let's see, well, on a shape.
The shape has all these things.
It also has a Fill
Color and a Stroke Color
and it's using this
platform color.
And again, like what
Cortis is talking about,
let's see, let's go down.
This is about-- this
my archiving code.
This is when I-- how I
init in from the archive.
Let's hide this to
easier to see.
So you can see, I'm
using-- when I encode it,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I'm actually using a CIColor
to archive it to a file
because that's something
that exist on both platforms.
So that's something I can use
to make a consistent archive
so I can open the same
document on both sides.
So if the models are the same,
what is the controller
level look like?
So on the view side,
it looks very similar.
I've got a Document
View that respond--
that corresponds to the canvas.
I've got a Shape View that
corresponds to each shape
and these are both
subclasses of NSView.
And then on the controller
side, I've got a single document
because there's some--
the document can serve as the
controller for the whole thing
because there are not other
screens that could show up.
And the document really
only has support for--
really only need to do things
like it has some undo support.
And then it does-- this
is the data, same code.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So this takes the archiving
and then it reads it.
So I can build this and
I'm back to my same data
and I should mention that I
can also do keyboard shortcuts.
So if I can do Command-Z,
see the Edit Menu Flash
and those shapes go away.
I can also go back
up here, do the redo.
This is all again for free just
by using NSUndoManager,
my model.
And I can use keyboard
equivalence.
These are custom
things that I set up.
I can use keyboard
equivalence to change the shape.
And these are things that
our users are going to expect
when they come to
your application.
So I'm going to hand it back
over to Cortis to finish up.
Thank you.
[applause]
>> Thanks Dan.
That is some amazing work.
He's a fast coder isn't he?
OK. So, like I said before,
there's three things I'd
like you to take home today.
Number one is I want you
to rethink your iOS apps
in terms of OS X apps, OK?
So there are some changes that
you'll need to make there.
Number two, restructure
your code
so that your model is cleanly
separated from your view
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and you're controller.
That way, you'll be
able to take advantage
of the maximum code
reuse possible.
And three, just get started.
You know, your customers
are going to love it
that you have an
OS X app especially
if you integrate your iOS
and OS X app experience.
So that's going to be great.
If you want more information,
please take contact
Jake Behrens.
He's awesome.
He will answer your
emails maybe.
I think he will.
>> He will.
>> He will, he says.
OK. Documentation, go
to AppKit documentation
at developer.apple.com/mac.
For the User Interface
Guidelines, this is important
because this is going to show
you how to make a great Mac app.
So go to that one.
That's developer.apple.com/ue.
The Developer Forums, a great
place to talk to developers.
We've got real developers there.
We haven't put Siri to work yet
there but real Apple developers.
Some great talks to look at.
So we have taken control
of Auto Layout in Xcode 5.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
If you want to know
how to do X--
Auto Layout, that's
a great one to go to.
There are lots of also
talks from previous years
that you're going to have access
to on your WWDC app
for Auto Layout.
Introduction to SpriteKit, I
made a plug for it earlier.
That's going to be great
if you're doing any kind
of cross-platform 2D Game.
Best practices for Cocoa
Animation, that's a great place
to go to for information
on NSStackView
for core animation
changes and for things
about auto layout as well.
And we'll give you a few--
things about animation
and auto layout.
And then Introducing TextKit,
and then we haven't talked
about that at all
in this session
but if you've attended some
of the earlier sessions,
you'll probably be
quite pleased.
But we didn't really
talk about that
but the TextKit is
actually implemented
on the same fundamentals
as the OS X Cocoa Text.
So, all of the things that you
can do is Cocoa Text or sorry,
in TextKit that you've
learned about, you can also do
in Cocoa Text and your code
is going to be the same.
So, your NSLayout Managers
and your NSText Storage,
all of that is on OS X
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and you're code can
be largely the same.
Thank for coming.
Enjoy the rest of your show.
[Applause]
[ Silence ]