WWDC2013 Session 228

Transcript

X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[ Silence ]
[ Applause ]
>> So many people,
this is awesome.
Thank you very much
for coming out.
So, it's Friday, as
you probably noticed.
And, you know, 'cause
it's Friday,
we thought we'd do
something a little different,
have a little fun.
You all got the note that today
is Audience Participation Day.
Did you saw it in your--
I just made that up.
But, no, seriously,
audience participation.
So the first thing,
if you'd help me out--
by the way, my name
is Scott Stevenson.
I work in Apple Engineering.
Thank you.
So, if you would help me
out, just by show hands,
how many people here today
consider themselves sort
of beginner, just getting
started with iOS or OS X?
No beginners, really?
Two, three, OK, all right.
We're going to see-- you
think you're really good,
but we'll see.
So-- And who considers
themselves sort
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of like intermediate,
like pretty good but
not total expert?
Wow, OK, all right.
See now, we're being honest, OK.
What about like total expert,
like people there's no way
you're going to learn something,
you're just here to like
heckle the other guys?
OK, all right.
So you guys are going
to learn something.
So, here's my-- here's the deal.
My goal is to make sure every
single person in here learns
at least a few awesome things.
And the AMB guys and the
first two groups, you guys--
your job is to watch
the other guys.
And if they learn something,
'cause I'm going to check later,
then I want to hear about it.
So, the first thing
I want to say here
at the beginning is how many of
you know about NSHipster.com?
OK, yeah. So right, so you
guys know the deal with this.
But just in case you don't, the
thing here is that the author,
Mattt Thompson, what he
does is he goes out--
and of course, Cocoa and
Cocoa Touch are these really
like expensive rich frameworks
with so many things available,
and you're-- it's likely that
because there's so much stuff,
you're actually going to
miss some really cool things.
So, what Mattt does, he's
been doing this for a while,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
he goes out and digs up
these really, you know,
amazing gems hidden in Cocoa
and Cocoa Touch and brings them
to the surface and says, "Hey,
you guys really should be using
this 'cause it's awesome."
So we ran across the site and we
said, "Well, this is super cool.
Let's do a session on this,"
you know, 'cause that seems
like a really good idea.
And so, we called Mattt
and we're like, you know,
"Would you want to come up
WWDC and talk about it?"
He's like, "Sure,
that sounds good."
So we actually brought him
today and I'm going to bring him
up in a little bit, but
I just want to call this
out in the beginning
and just, you know,
give credit where credit's
due that this is sort of based
on something Mattt did.
So, we have 30 tips.
So remember the expert folks
that appears you're not going
to learn anything,
remember below of averages,
pretty good chance you're
going to learn something
and you're going to see
them counted down as we go.
So, here's the little
map here that we did.
We have a graphics
team as you can tell.
And-- So we're going to cover a
bunch of different frameworks.
We're going to start at Xcode,
Objective-C, and then kind
of work our way up to
the different levels.
And we'll eventually end up on--
I guess that's like
AppKit Peninsula
or something like that.
So let's start with Xcode and
we're going to focus on editing
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and debugging to start.
And we're going to kind of start
with some more basic things
and work our way up
to the advanced stuff.
So to start, if I can get the
clicker to work, there we go.
So, I'm sure a lot of you
are familiar with the feature
in Xcode called Open
Quickly, and you just bring it
up by going to the File menu
and choosing Open
Quickly of all things.
And you can also just
hit Command-Shift-O.
And what happens
is you choose that
and you see a window
like this pop.
This is Xcode 4, of
course, so, you know,
it looks a little
different than Xcode 5.
But this window comes up
and then you just go ahead
and start typing something.
And what Xcode is going to
do is it's going to look
across all the code in your
project and all the frameworks
that you brought in,
and it's just going
to start live filtering results.
And I'm sure a lot of
you are actually familiar
with this feature.
If you're not using this, you
definitely should be using this
because compared to like
Project Search where you have
to type something and look at
the long list result and say,
"Ah-ah, that wasn't
quite what I wanted.
Let me delete it
and do it again,"
you're live filtering
stuff in Open Quickly.
So you should be using this
like all the time, all day.
But the thing you
may not know is
that it's actually
pretty incredibly smart
for what you're searching for.
So, in this example on screen,
I've typed coretextctpar,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and Open Quickly is
smart to say, "You know,
I think what you actually meant
was the CTParagraphStyle header
in CoreText," so
it splits that up.
So, another example is you
can type in abbreviations.
So you can type in UK/UIVC,
and again Open Quickly is like,
"You know what, I'm pretty
sure what you actually meant
was UIViewController."
So, it's going to go
ahead and highlight that.
There's other options,
but that's the one
that pops up to the top.
Next tip-- by the way, since
we have 30 tips, we've got just
about an hour, I'm going to
have to race through this
in case that's not clear.
So next tip, this is
one of these things
that I see my coworkers
everyday using
and every time I see
them using, I'm like,
"Why am I not using this?
This is so useful," and
that I'm just wasting time.
They're like done and
I'm like going to lunch.
So, all you have to do is in
the upper left hand corner
of the Xcode Editor pane,
there's this tiny little,
really not super obvious button
but incredibly useful
called Related Files.
So if you click on it, it
pops up and shows you files
that are related to the
cluster you're currently working
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
on which is a great thing for--
to you based on what I'm saying.
It shows you Subclasses,
Superclasses, Categories,
and one of the most
useful items actually
in here is the Callers
and Callees.
So, other classes that
are calling this class
and other classes you
call are actually listed
in that menu item.
So you should always be
using this all the time,
[inaudible] thing here
so I remember to use it
so I'm not wasting so much time.
Next trick-- and this honestly
is another one of these things
where I wish I'm really
just putting this here
so I remember to use it.
So a lot of times what happens
when I'm debugging something
is I'll get kind of halfway
through my debugging session
and I'll be thinking, "Boy,
if I got just one thing I need
to actually have here to help me
through this problem," and
so I'll like typing in NSLog
and stop and recompile,
and then I'll be like,
"Why didn't I use Breakpoint
Actions 'cause this is
so much better?"
So all you need to do to
use Breakpoint Action is go
to the line of code
where you need
to log some additional
information,
just pop in a breakpoint.
And if you right click
on the breakpoint,
it will pop up this popover.
You can do a bunch of things
with this just pop over,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
but the one thing I just
want to highlight here is
that you can actually
just add a log message.
So, just use Log Message,
type in whatever the format
string is that you want.
And you can actually do
some pretty cools things
with conditionals and the number
of times to skip the breakpoint.
But anyway, you can type in a
log message and you don't have
to stop running the program.
It can just keep
going, of course,
'cause this is a breakpoint.
So, do not-- from this day on,
do not stop and write NSLog
and recompile, just use this
'cause it'll save you tons
of time.
Debug description, just
a really quick one.
I'm sure actually a lot of you,
hopefully, are aware of this.
So of course there's
the description method
that you implement on your
classes just to see something
in the console when
you use NSLog.
But debug description is
a little bit different.
So it's intended to be kind of
more provost debugging string
that gives you extra information
that you only really
need at debugging time.
So it just looks like this.
This is not rocket science.
You implement a method
called debugDescription.
You return some ridiculously
long string
that you think you might need
to print out for some reason.
And then when you're
in lldb or in the--
just in the Xcode
visual view and I do a po
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
on self.rootViewController here,
I get that really long string.
So of course, you're not getting
the normal just description
which you may be using
for other purposes,
it's just for debugging.
And these are for Breakpoint
Actions, that's obvious, OK.
One more quick hit in case you
guys are not familiar with it.
There's a method you can call
called recursiveDescription
on View Hierarchy, and it
will give you back something
like this.
So you can actually
see the complete layout
of your View Hierarchy just
sitting there on the debugger
which is ridiculously useful,
so you should be using this.
OK, [inaudible].
[ Pause ]
How are we doing?
Are we learning stuff already?
Did somebody learn anything?
Hands. OK.
Just wait, there's more.
OK, so we're going to
work our way up now.
We're going to look
at Objective-C stuff.
So, just a quick refresh
on what Subscripting is.
I don't-- I think most
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of you are probably
using it at this point.
But it was something
really nice added in--
recently to Objective-C.
So a typical use case here is
I have an NSMutableArray called
in indexedValues.
And using the new subscripting
syntax which is, you know,
very common to people from
other-- or very familiar,
I should say, to people
from other languages,
you can just use this
nice little bracket thing.
So don't have to say
like objectAtIndex,
you just say in bracket zero.
You can give values
out, set them.
That's all totally
straightforward.
And of course, you can do the
same thing with dictionary.
So that's just a little review.
That's not the actual tip.
The tip is that you can add
this to your own classes.
And I'm pretty sure most
people based on who I've talked
to don't actually even
know you can do this.
So, here's how it works.
I'm going to make up a fake
class here called Record Set
and I'm just going to
add a property here
called indexedValues.
You could have anything
[inaudible] as much as here,
and you got two methods.
So the first one is called
objectAtIndex subscript,
and you can actually see
this declared in NSArray.
And then the setter, you don't'
actually need the setter.
But if you want the setter,
you implement
setObject:atIndexedSubscript,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and then I'll just close
up the class like that.
But it says-- oops, jumped
a little ahead there.
Oh that's OK.
But just those two
methods that back this,
and then the implementation is
just whatever you want to do
to get that object
to that index.
In this case, I've just looked
at my indexedValues property
and pulled out the value
and I set in the setter,
and here's how that
looks in use.
So I'm making-- just an instance
of my fake record
set class here.
And then after if
it's initiated,
I can just use this
subscripting syntax directly
on my class which
is pretty cool.
You could imagine
this would be--
I called it records
out here just to kind
of suggest it might be kind of
cool for like a dataset coming
from a database, that sort of
thing, you know, so I can set it
and get it, not super
rocket science.
And you can do it for
keyed subscripting too.
So, it's going to look very
similar to the last example.
In this case, I made
a person class.
And actually I'm backing it
this time by a dictionary.
But again, it doesn't
have to be backed
by a dictionary or an array.
It can be anything that you
need to accomplish a task.
So again, there's two methods,
objectKeyed [assumed spelling]
subscript instead of index,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and setObject:
forKeyedSubscript.
And these also are declared in
NSDictionary if you just want
to copy and paste them.
So it's just those two methods
you need for the declaration.
And the implementation is
really not very surprising.
Again, you're just using the
regular dictionary method set
and get the objects.
So, that's pretty
straightforward.
And here's just a quick little
example of how it works.
You say, you know,
person favorite color,
and you might be kind
of wondering, "Well,
why not just say
person.favoritecolor?"
This is a literal string, but
you can imagine a scenario
where you're fetching
something from a service
or you're pulling
something out of a database,
and you may have actually
know those keys ahead of time,
so this will be a useful way
to kind of to simply, you know,
put those values and
get them back out.
So, that's pretty cool.
But, hey, you know what
would be really cool is
if you can actually use
both at the same time.
So, I heard some clapping
there, that's awesome.
So, I have just one more fake
class here called Ultra Record
Set because it's inappropriate.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So, I've got indexedValues
and keyedValues, and this is--
you know, I bet you can see
where the plot is going here,
objectAtIndexedSubscript
I implement both
of the indexed ones, I
implement with the keyed one,
close it out, it all just
works, so you would expect.
And then, of course-- let
me get the clicker to work.
And of course, I'll just
make an instance of this
and I can just go ahead
and start setting,
getting those values the
same way I did before.
So, all that, you can
just go home and use that
and have fun with that.
OK. A few quick things,
so these are--
everything so far as
being kind of additive.
This is reductive.
So in versions of Xcode
prior to 4.3, and really just
like the entire lifetime
of C, if you wanted
to call a method inside of--
like a private method inside
of a file, you would have
to declare it somewhere
'cause the compiler would
like somehow not be
able to figure it out.
But guess what, since Xcode 4.3,
you actually don't
need this anymore.
So, if you have a private
method that you're calling
from within the same file,
you don't need to declare it.
The compiler will figure
that out, so that's good.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And this is-- maybe more of
you are familiar with this,
but since Xcode 4.4, you would--
you can of course
declare properties.
And then in earlier versions
of Xcode and Objective-C,
you would then synthesize the
accessor if you wanted to set
and get those values
automatically,
if you want the compiler to
make the accessors for you.
Since Xcode 4.4, you don't
even need this anymore.
So, go delete all that, we
did/ so I recommend that,
[inaudible] your code.
OK, so as I promised,
we pulled Mattt Thompson
out from the NSHipster hole
or whatever it's called,
NSHipster Cave, I'm not
sure what it's called.
And he said he would come up
and show off some cool things.
So, I'm going to
bring Mattt out.
Thank you.
[ Applause & Inaudible Remark ]
>> Hey everybody.
Good morning.
My name is Mattt Thompson
and I am an NSHipster.
And today, I'm very
excited to show you some
of those Xcode tips that
Scott just told us about,
and my favorite new
addition to Xcode,
something called Instance Type.
So, let's switch over to this.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
All right, you can see code.
All right, this is a
very simple project.
We have an employee class.
Well actually, let's use Open
Quickly employee.h. There we go,
pretty nice.
We can also use our assistant
things, so we can see the .h
and .m on the same view.
Pretty simple, we have
a name and a salary.
But here, we have
a common pattern.
It's a class constructor,
convenience method
that returns an instance
of an object initialize
with, in this case, a name.
This is just a short-hand
for alloc-init and setName.
The thing here though
is that we have ID
as being the return type.
So, let's kind of
illustrate what kind
of problems you can
get into with that.
We'll go to main.m. All right,
let's say we have employee,
employee with name, and I'll
employ myself, all right.
Here, you know, Xcode is--
doesn't have any sort of idea
what kind of objects returned.
It just knows that the
returned type is ID.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So, I could do for
instance add object.
What? That doesn't
make any sense.
I can build and it's
not going to complain.
It's going to say it succeeds.
But of course if I build
and run, and I'm going
to get immediately,
you know, [inaudible].
That's terrible.
So how can we improve on this?
Well, up until recently, kind of
the suggested pattern might be
to let's say, OK, go
to-- back to employee.
Instead, return just an
instance of employee, right?
So we have our employee object.
We would change it in our
implementation as well.
And then if we go
back to main.m,
if we have this method
here, let's say add--
well, it's doing add observer.
So we know that it's
not responding.
It knows to narrow
down the selectors
to only NSObject and employee.
But let's say, you know, I
give myself a permission.
We have a manager class too.
So manager is a class, no
real implementation here,
just a new property,
subordinates
because I have subordinates, I'm
a powerful man now as a manager.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So-- And again, we
don't have to, you know,
synthesize our property.
So back to main.m,
say it's manager,
so I'll make myself a
manager, and I do set--
well, setting salaries
is kind of cool.
I'll keep that one for later.
If I do set subordinates,
you know,
it's not completing, darn it.
No, no, OK.
So, what's going on here?
Well, manager-- employee
with name,
that's for turning an employee.
What I want is manager.
But if I went back to ID,
I'd still be, you know,
you understand where
this is going.
So, we have something
called Instance Type.
If we go back to employee, we
change this to Instance Type.
It's sort of the Goldilocks
kind of return type.
It is the flexibility of ID, but
you still get the type inference
of kind of doing an explicit
declaration of the return type.
So in this case, it's saying,
"I will return whatever
class kind of called this."
So, if we go back and make sure
to fill out our implementation
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
as well and then back to
main, now if we do this,
I can set subordinates.
Hey, check that out.
So Instance Type, it is
the perfect kind of way
to do class constructors.
And you'll notice that in the
API divs for iOS 7, Mac 10.9,
there's a lot of methods.
Although previous class
constructors that were using ID
like NSArray array, they're
all now using Instance Type.
So using your own
code, clean it up,
it's really a convenient
thing, and I'm going
to pass back to Scott.
We're going to talk about
some Foundation stuff.
So, yeah.
[ Applause ]
>> All right.
Learning things, all right, OK.
So, move on.
So we're going to
talk about Foundation.
So we've worked our way up
from Xcode and Objective-C,
and now we're getting
into the frameworks.
And for the most part,
everything we talk
about for the rest of the talk
and really everything
we've talked
about so far applies
to both iOS and OS X.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So everything for iOS 7,
everything from Mavericks,
all these should apply.
So you can keep that in mind.
We have some iOS specific stuff
and AppKit specific
stuff at the end.
OK, so Foundation.
Let's jump on to this.
So, a lot of you I'm
sure are familiar
with Grand Central Dispatch.
This is great technology
we added a few years ago
that allows you to breakup
work into individual work units
and distribute them across
whatever resources are available
on the system, so
it's really great.
But I don't know how many
of you are actually familiar
or are using NSOperation.
It's this really great
object-oriented API that sits
on top of Grand Central
Dispatch.
So, all that really super cool
performance stuff that you get
from Grand Central
Dispatch, NSOperation offers
with all the Cocoa
Objective-C goodness.
So, in addition to
that really nice API,
it also has some features
that are unique to NSOperation
that you can't just-- you
can't get using just Grand
Central Dispatch.
So, for example, you
can cancel queues.
So, you can have stuff running
out there and you say Cancel
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and it will stop running.
I mean if you're subclassing,
you have to do that in your side
as well, but it's
available to you.
You can also set max number
of concurrent operations
at the same time.
So, you might have tons and tons
of hardware and you say, "Well,
a hundred concurrent
operations is fine here.
But if you're stilling it down
to a mobile device, I might say,
well, maybe four
concurrent is good."
And you can set up dependencies,
and this is super cool.
I'm going to show you an
example of this in a second,
but you can actually take
different work units and say,
"I really do not want
this one to even start
until the thing it
depends on has completed."
And of course, I
mentioned Objective-C APIs,
so that means you can subclass
it, you can add categories
to NSOperation, and you can
use even key-value observing
to monitor the state of the
operations as they're running.
So, it's a great way to cleanup
your code and use for a--
sorry, build a more
robust source base.
So, here's a really
good example.
I'm sure a lot of you are
actually familiar with this app.
This is the WWDC
app running in iPad
and we used NSOperation
here in an interesting way
where you may actually
anticipate.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So we use the Dependencies
feature in NSOperation
to specifically make sure that
any time we go do a request
to the server for things
like to fetch your favorites,
to find out which sessions
are currently available
or to get the information
on session,
we set up a dependent operation
that first authorizes the user.
So, anytime we go
out and do that feed,
before we actually
launch that operation,
we set a dependency
on the authorization.
So, here's what it looks like.
This is code, it's almost
directly from the source base,
so I cleaned it up a little
bit so it fits on the slides,
but it's pretty much
true to form.
So, just walking through
this, I have this method
that says addDependencies
ForAuthorizedOperation.
I'm creating these
authorization operations,
sounds like Dr. Seuss.
And then I add it
as a dependency
on the operation
being passed in.
So might be passed in, for
example, like set of favorite.
And then I add the off
operation-- author--
off operation to
the operation queue,
and that's all I
need to do here.
And then I have the zipper
method which is setFavorite.
I create that operation.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I instantiate it with the
block I'm going to use.
Set favorite status, and then I
call this method I've defined.
So, if you think through
this, it means that anytime
that we want to go ahead and
do an operation, I just call,
set the method and says,
"Whatever you do, just make sure
that the user is authorized
before you go do this."
So it's a great way to
kind of cleanup that logic
and make all these independent
work units work together
for you.
And add to queue of course.
OK, NSExpression.
So, I'm sure a lot of you
are familiar with NSPredicate
which is used in Core Data and
it's used in different places
if you're filtering
arrays for example.
But NSPredicate is
actually built
up by individual constituent
parts in NSExpression.
And this thing is really cool.
I'm going to show you.
By the way, this is one of
these things, when we're working
on the session, there were
four of us working on it,
and every one of us,
when we were trying
to brainstorm the
ideas, we're like,
"I didn't know you
could do that."
And we've accessed the source
code and we didn't know that.
And this is one of those.
So, NSExpression can actually
parse mathematical expressions.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So here, I've got 3
plus 5 times 4e10.
And if you've ever messed
around with this spotlight menu
in the upper right hand corner,
you've probably discovered you
can actually type mathematical
expressions in there.
So this is that same thing.
And this is actually
pretty flexible.
I was blown away when I
was trying it yesterday,
square root, you know,
syntax, all that kind of stuff.
So you just say NSExpression
WithFormat,
you pass in your text, of course
you can pass in a variable
if you want, I didn't in
this particular example.
But then you just evaluate
the value, print it out,
and then you get this
really, really big number.
So that's pretty cool.
So you can imagine, if you
wanted to have the user type
in some sort of mathematical
equation,
you wanted to show them the
results, so there's going
to be a bazillion math
apps now, I'm sure,
but that's actually
available to you if you want.
It's going to be
the new flashlight.
OK. So-- yeah, flashlight
fans, yeah.
It's a great app.
OK. So, in addition to
our friends, NSArray
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and NSDictionary that
we're using all day long,
you should also be using
NSSet, NSOrderedSet.
And there's some very
specific scenarios
where they work really well.
If you're not familiar
NSSet, OrderedSet,
you don't really know the
details, basically one
of the key things they do is
they guarantee uniqueness.
So with an array
or a dictionary,
you can have multiple
instances of the same object or,
for example, like two NSNumbers
of the value of 2, you know,
you can have those
across the entire--
you know, multiple instances
of those across the collection.
But NSSet and OrderedSet
guarantees you'll have a unique
one instance of a
value throughout the
entire collection.
So, the other thing it
does that's really great
and in particular for NSSet
is if you need to check to see
if it-- like, for example, an
object has already been loaded
into memory so it uses as a
cache, checking for membership
in an NSSet is practically free.
So there's absolutely
no reason to not use it
for that sort of thing.
And I actually just talked to
somebody in the labs yesterday
and they were blown away
that this was so fast.
So this is really, really good.
And there's also something
interesting you can do
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with set calculations
that are not available
on array and dictionary.
So here's an example.
You can do intersectsSet, so you
can take one set and another set
and see, you know,
do they intersect.
You can say, "Is this
is a complete subset
of the other set?"
You can do a -minusSet.
You take one set and just
remove the entire contents
of the other set.
And you can union them.
So this-- on the surface,
it says, "Yeah, yeah,
that's great," but
think about that.
That means that you don't
actually have to loop
through the arrays and do
all the stuff yourself.
You can convert them to sets.
You'll guarantee that
they're all unique.
And then when you've
actually run these operations,
you'll going get the final
set of the thing you need.
So this is really, really good.
The one thing just to keep
in mind is before you
go converting all your
NSMutableArrays to
NSOrderedSets,
NSMutableArray is
faster at adding objects.
So if you just need to add a
lot of objects, continue to use
that as MutableArray and you
can switch back and forth
when you need to filter them.
All right.
Oh also, I just want to mention,
there was a talk right
before this one, I don't know
if you were in the room, but
you should catch on video
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
if you didn't see
it, Designing Code
for Performance,
so Quinn gave that.
And it dives into how to use the
Foundation collection classes
to have really, really
fast codes.
So you should definitely
check that out.
OK, so a few quick hits here
for different collection things
you may not be familiar with.
We'll just kind to go
through this real fast.
I see 11 on this slide.
It really should
count for like 15, so.
So, reverse arrays
inline quickly.
So I just have an
array of numbers here
and if I call
reverseObjectEnumerator,
usually when you get an
enumerator from array,
you're going to look through it.
But in this case, I'm just sort
of borrowing one little method
from it which is
numbers.reverseObjectEnumerator,
we should get the reverse order,
and then I just call allObjects.
So we don't actually have
to loop through that.
I'll just get the complete
set of reversed object.
So that's good.
A lot of times, when you're
implementing a method,
you're passed in some sort
of value and need them mutate
that array or you need to
mutate that dictionary.
And a common pattern that I see
is you may want to check to see
if that value you're
being passed in is nil
because if you call
mutable copy a nil,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
you're going to get nil back.
So that's not really helpful.
So instead of doing that,
you can just say
NSMutableArray arrayWithArray.
And even if it's
nil, you're going
to get a MutableArray back.
And that's a case for most
of the collections classes,
dictionaries, NSSet,
OrderedSet, OK.
Another scenario
you might yourself
in is you might be passed
in one of any number
of collection objects.
So for example, you
might have a method
that takes a dictionary
or an array.
And there's sort of this
question about, "Well, you know,
how do I declare that?
Do I-- is it like an id or
an id component to NSObject?"
Well, what you can do is
just specify id conform
to NSFastEnumeration.
The only thing you need to do is
actually just iterate over it.
This is absolutely
perfect for that.
So that can be almost any
collection class that we have.
And, interestingly enough, you
can do this on your own class.
So again, if you're thinking
about that record example
that I showed you before and
you want to actually enumerate
through them, all you have to
do is implement this one method,
countByEnumeratingWithState,
objects count.
And it turns out that
the implementation is
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
incredibly simple.
If you have an array, you
just call that on the array.
So, there you go.
So, now, I would like
to bring up Mattt.
And you probably--
when you saw his demo,
you might have been thinking,
"Yeah, yeah, I knew that."
He's going to show you
some stuff I guarantee you,
you do not know.
I did not know it,
none of us know it.
So, he'll bring that back up.
>> All right, so Foundation
and Core Foundation,
two of my favorite pieces of
software in the whole world.
Let's talk about
some obscure stuff.
Well, first of all, let's--
at the outset, let's say
Objective-C really sits
at the interface between the
procedural world of C, you know,
the really strong foundations,
but it also combines
that with the object-oriented
paradigm inspired by small talk.
And right at that interface
is a class and its value.
You might be more familiar with
its subclass, NSNumber which is
in an object representation
for things like ints, floats,
doubles, and Booleans.
But NSValue, you know, still
has a few tricks up its sleeve.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
For instance, it can store
all those scalar values
but it can also store
things like structs.
Specifically, you might be
working with structs like ranges
or point, sizes and rects.
And then one of the
other things that it does
that actually very
few people know about,
it can also return
unretained references,
and I'll show you an example of
how you might use that later.
So, another tip.
Let's say you're trying to
construct an array and you want
to have a whole bunch
of different, you know,
C-values in it, so
this is how you do it.
So you have a MutableArray
using the subscripting here,
just adding, you know, values,
valueWithPoint passing
a CGPoint,
valueWithRange that's
passing in an NSRange.
Let's say you have a custom
struct here, you know,
if you don't UIColor
for some reason,
you just want this
RGB triple, right?
You have red, green and blue
values, and you have an instance
to that, you can encode
that and put into an array
by doing NSValue valueWithBytes
passing a pointer to the color,
and then Objective-C
type using the @encode
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and then the type of the struct.
Whenever you're using
NSMutableDictionary,
another kind of collection,
you know, it's simple.
You do a Key equals Value.
That's works really well
whenever Key conforms the
NSCopying and because
NSMutableDictionary copies
its keys.
That does not work so
well for some objects
that don't conform to NSCopying.
And you might not be
able to think of any,
off the top of your head,
but certainly if you'd gotten
into a situation where
you're trying to do this
and you're trying to figure
out why this doesn't work,
this is a lifesaver right here,
NSValue
valueWithNonretainedObject,
you pass it in, it will
just work magically,
just assume that the object is
being owned by something else,
everything works
just marvelously.
Let's talk about
Key-Value Coding.
Key-Value Coding is
another really cool feature
of Foundation.
You know it, you love it.
valueForKey, name, it's an
equivalent to emloyee.name.
The thing about Key-Value
Coding, of course, is it's a way
to dynamically set and get
properties and also, you know,
traverse object crafts too.
So, valueForKeyPath,
manager.name, that's equivalent
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to employee.manager.name.
All right, you guys
already know that.
That's not the tip.
The tip here is that you can
also do this on collections
and by passing in
Key-Value Coding, you know,
doing that on a collection,
you'll actually get the result
for each objective
in the collection.
So here, we have an array of
words, Alpha, Bravo, Charlie.
Let's do valueForKey,
uppercaseString.
You get an array of
the uppercased words.
Or, let's say you do length.
This is actually
really neat, right?
So, Key-Value Coding
automatically boxes
and unboxes values into
their object representation.
Length normally returns
an NSUInteger.
But in this case, you can see
that we have the @5, @5, @7.
We have NSNumber
representations of that.
So, really useful, you stay
within the object paradigm.
Another cool thing
you can do here.
So, it's often the case
that you will be making app,
especially like iOS apps,
you're going to be interfacing
with some sort of web service
API and maybe encoding,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
you know, serializing values
from JSON into an object.
Instead of doing
that boilerplateself.name=json
[assumed spelling]
valueForKeyName,
you can use this
dictionaryWithValuesForKeys.
And you can-- you know,
it's kind of a shortcut
for all that-- or
sorry, that's the way
to serialize it, I guess.
So, you can create a
dictionary representation
of an object using
dictionaryWithValuesForKeys,
the keys that you want to
serialize out, maybe send back
to that web service
and then pass
in that resulting NSDictionary
to NSJSONSerialization.
And then that
setValuesForKeysWithDictionary,
that's where you'll be able
to serialize your
object really quickly.
Really neat.
That's just assuming, of course,
parity between like your JSON
keys and your property names.
Let's talk about KVC
Collection Operators.
You might have seen
this in the wild,
but may not have had a
chance to use these yet.
So the most common one you
might see is valueForKeyPath
and then you say, "Here's
a collection colleagues,"
and then .
@count. Some other examples
of this you might have,
the @avg.salary or
the max.temperature.
So there are three kinds
of collection operators
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and they are kind of
distinguished based
on the different
return types they have.
Simple collection
operators return objects.
Object operators return arrays.
Maybe a count or two,
but it'll all make sense.
Array and set operators
return either arrays or sets.
And the syntax for
this is something
that you might find
yourself looking often.
I know I have this
bookmarked in my documentation.
You have on the Left Key
Path, however to get--
the way you get to
the collection itself.
So in the middle,
you have the dot--
these are all separated by dots.
You have @ and then the
collectionOperator itself.
And then on the right, if you
want any aggregate properties
on the result of the
collectionOperator,
you both head to the right.
Again, you'll be
looking this up often.
It's just one of those
things that it takes a while
to get into your head.
All right, so Simple
Collection Operators.
We have, again, count that'll
give you the number of elements
in your collection
represented by an NSNumber.
You also have sum and average.
So for collections of NSNumbers,
it'll give you the, you know,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
arithmetic sum and average of
the numbers in that collection.
I think the two most useful
and interesting ones
are max and min.
These don't work
just on numbers.
They work on any object
that implements compare.
So you can have the max
and min date, or the max
and min weather, or the
max and min whatever.
It's a really cool
and convenient thing
that you can add to your own
objects and take advantage of.
We have Object Operators.
We have unionOfObjects and
distinctUnionOfObjects.
The difference here is
that distinctUnionOfObjects
will unique the resulting array.
An example of this in
code, let's say you want
to remove all the
duplicate values in array
without actually passing
it through an NSSet first.
The way you do that is that
you do array valueForKeyPath:@
"distinctUnionOfObjects.self".
And that's actually a cool tip.
You can pass self in for
different situations and kind
of use these different operators
on collection, you know, itself.
So, finally, we have
Array and Set Operators.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You have unionOfArrays,
distinctUnionOfArrays,
again just like the
previous one,
and then distinctUnionOfSets.
Sets, of course,
everything is distinct.
So there's no non-distinct
version of your--
and the return type is going
to depend on what you pass in,
arrays for arrays
and sets for sets.
Let's kind of illustrate,
this is an example.
This is for flattening out
values within sub-collection.
So let's say I have an array
with two color schemes here,
some beautiful color schemes.
If I do valueForKey
unionOfArrays,
it'll look like that.
So it's taking the two arrays--
the subarrays and putting them
into one flat array values.
Or if I do
@distinctUnionOfArrays,
we now just have the four
distinct colors in an array.
Let's talk about NSDataDetector.
So in Mail, you might notice
that whenever you have an email
message with certain kinds
of information, that
information will be highlighted.
And by clicking on
that information,
you can very easily add
stuff like a phone number
to your address book or
a date to your calendar.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Very convenient.
The coolest thing about this is
that NSDataDetector is
underneath the hood of all this
and you can add that to
your application too.
So NSDataDetector,
it's the sub-class
of NSRegularExpression.
But instead of passing in
kind of arbitrary formats,
it has kind of these
pre-calculated, really,
really complex regular
expressions to find dates,
you know, relative dates or, you
know, any sort of date format,
addresses, links, both URLs and
email addresses, phone numbers,
and transit information,
like flight numbers.
So this is really, really cool.
Let's show how this
works in example.
So we have this string, right?
We have obviously an address
in there and a phone number,
and we have this error.
We're going to pass it in when
we initialize Data Detector.
And you see that when we have
initialized this, we're passing
in the different types of
information to look for.
When you're creating this in
your application, you only want
to pass in the types
that you're interested
in because each additional
type will incur a little bit
more processing.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So in this case, we're
only looking for--
well, I guess that should
be address and phone number.
And then of course, because
it's an NSRegularExpression
sub-class, it's using
that familiar
enumerateMatchesInString method
with options, range, and
then enumerating each time
with a block.
In this case, we're just
locking up the match.
All right, and finally,
we're going to talk
about CStringTransform which
might be my favorite thing
in the whole of Cocoa
and Cocoa Touch.
It's obscure, it's powerful.
It's like perfect, all right?
We have great string
APIs and it's a shame
if you don't know about them.
So CStringTransform,
it's a multitasker.
It will strip accents
and diacritics.
It will name Unicode characters.
It will encode XML hex entities
which is useful if you're ever,
you know, making
XML or decoding XML.
And you can also transliterate
between writing systems
which is kind of mind-blowing
whenever you see it in action.
So here it is, meet
CStringTransform.
Of course, it's a C-Function,
CF coming from Core Foundation.
It's returning a Boolean whether
or not it was successful.
The first argument is
a CFMutableStringRef
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
which you remember
that NSMutableString
is toll-free bridge.
So this makes it really
convenient to work with.
The range that you're going
to put the transformation
on is Next.
And if you're just doing
it on the entire string,
which you normally are,
you just pass a Null.
The kind of transform
is the third argument.
We're going to get into a couple
of the constants you
might pass in there.
And then some of those
transformations can be reversed.
And if they are,
you put a Yes there.
So if you were in English,
English doesn't get all
these cool characters
which is really a darn shame.
But as a result of that, of
course, even the bigger shame is
that most applica-- or a lot
of applications can't
handle this kind of input.
We need to normalize
that into something,
you know, the base ASCII set.
So, you know, if we're going to
turn that into that, you know,
something that is
more processible,
we can use CStringTransform.
So we do CStringTransform
but passing
in the kCFStringTransform
StripCombiningMarks transform.
It's a mouthful, but here
StripCombiningMarks is doing
both accents and diacritics.
The difference between the
two is sort of academic.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
In this case, it just
noted all the squiggly bits
and interesting cool
stuff is being removed.
Next, naming Unicodes.
Every character you see
on a screen corresponds
to some standard character
documented in Unicode.
Each one of those has a name.
Some of those names are known
like Latin capital letter A,
or you know, ornamented A
with the ring above,
or symbols Snowman.
But what about this,
Emoji, right?
We love Emoji but what the
heck is that called, right?
But now with CFStringTransform,
we can find out.
So let's put in the code.
Of course, because
Xcode supports Emoji,
you can put that right into
your code, take the mutable copy
of this pig thing and then pass
in the
kCFStringTransformToUnicodeName.
If anybody didn't learn
anything yet, you're going
to learn something now.
The name of that?
Pig Face.
[ Laughter & Applause ]
All right.
So finally, we're going
to talk about, again,
really, really cool stuff.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Translating between writing
system or Orthographies.
If you don't [inaudible] there's
really no way that you can begin
to understand how
that's pronounced.
So it might be convenient
to put into something
that you do understand, a
writing system that you do know.
CFStringTransform,
as you might expect,
does this pretty cool, well.
You can pass in that Korean
string we just saw and pass
in the kCFStringTransformToLatin
transform.
And what that will do is it will
transliterate from that Korean
to a Latin representation.
So that's how you say it.
Actually, we're just
saying "hello", "annyeong".
But that works for a lot
of the other languages too.
So you can transliterate between
Russian and Greek and Korean
and Hebrew and Chinese
and Arabic and Thai,
all sorts of these-- all these
languages, you can put them
into their Latin equivalent.
So it's sort of a super power
in a lot of ways, right?
You can now read any
scripts in the entire world
with CFStringTransform.
It can transliterate between
hiragana and katakana,
the two phonetic writing
systems of Japanese.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You can convert between the
two which is really convenient,
especially if you're
leaning Japanese or want
to make a Japanese learning app
for instance, pretty cool idea.
Or you could turn it
into a Latin, you know,
the Romanization of it.
So even if you knew
about CFStringTransform,
you probably didn't know about
this techno way at the bottom.
I know I didn't.
I didn't read the--
you know, who reads all
of the documentation
from top to bottom?
But this note, you can pass in
any ICU transform ID as defined
in the ICU User Guide.
So all of the really,
really cool linguistic APIs,
they're using ICU, this open
source library under the hood.
So using-- you know, tying
into that, you can pass
in any arbitrary transform
ID into your third option.
So that means it's not only
do you get to convert those--
you know, transliterate
all those cool languages
that we showed before, but you
would do some foreign languages
that you probably have never
seen in your life before.
Things like, you know, Georgian
or Bengali or, you know,
Armenian or up there,
IPA, one of my favorites.
So it's a really cool and
powerful method and, you know,
[inaudible] actually show how
you might use this in action.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Let's say you've
taken Apple's advice
and you've internationalized and
localized your app to a bunch
of different markets and now you
have users all around the world.
You want to make sure that you
are able to handle, you know,
whatever they throw at you.
So here is a rather extreme
case where somebody is very--
you know, they're saying hello
in a lot of different languages.
Let's normalize that into a way
that we might be able
to like index later.
So first of all, we're
going to take that string.
To transform it into its
Latin equivalent, of course,
we're going to do the
kCFStringTransformToLatin.
Next, we're going
to get rid of--
again, there were a
couple of accents there
because Latin characters don't
encode all of the different--
it doesn't-- can code the
entire phonetic inventory
of all the different languages.
So, we take away those
with the kCFStringTransform
StripCombiningMarks.
Then we use CFString lowercase
to just turn it all lowercase,
really, normalize
all that input.
Finally, to get all
the words in that,
to get rid of all the
punctuation and white space,
we're going to use our friend
enumerateLinguisticTagsInRange
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
which, again, really
excellent API for linguistics.
You're going to pass
in your scheme,
so we're looking
for tokens, options.
No options here,
and we don't care
about the orthography argument.
And then in the block, we're
just going to iterate through.
For each match, we're
going to make sure--
we're going to see
if it's a word.
And if it is a word, we're going
to add it to that collection
of words that we created.
Finally, the output
of that, we have--
this is what we started out with
and then finally we have here.
So that's something
that you can read.
That's something you can
linguistically process.
It's just a powerful idea
of how you can use this
in your application.
So those are some of
my favorite things
in Foundation and
Core Foundation.
And with that, I'll
pass it back to Scott.
Thanks. [applause]
>> All right, so I think the
thing we've learned is there's
suddenly going to be an
explosion of math apps
and translation apps, right?
OK. So, we are moving
our way up to the layers.
We're going to get
to the really--
what I think is the really cool
stuff now, the UI Layer stuff
and eye candy [phonetic].
So let's look at Core Animation.
And real quickly, if
you're not super familiar
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with Core Animation, I'm sure
most of you have heard of it.
It's a framework data that
is actually just, again,
on both iOS and OS X,
and it powers all the
super cool animations,
the really fluid look
that defines the
iPhone, defines OS X.
It powers that by
staying on top of OpenGL.
So it's this really great, easy
Objective-C API that taps all
that power of OpenGL
so you don't have
to know all the low level C API
for OpenGL, so that's great.
And just a real quick primer
on what the key classes are.
There's CALayer which is the
thing that actually shows
up on the screen and
every UIView and in,
more recent versions of OS
X, every NSView has access
to one of these layers.
And a CAAnimation acts on that
layer over time, so it's--
for example, to change
the opacity
or change the color,
that sort of thing.
All right, so we're good.
What you may not know is
that there are some pretty
cool CALayer subclasses.
So CAGradientLayer
will actually animate
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
between different gradients.
Here, I'm simulating a sunrise,
but you can pass it
either an array of colors
or an array of colors
plus stops.
So, you can imagine, you
can go pretty crazy here.
And you can actually
[inaudible] things you want
to animate between.
So-- And it turns out, this
is actually ridiculously easy.
So here, I've actually created
an instance of CAGradientLayer.
I just chose some
random geometry,
but you can do anything,
obviously.
I have three separate colors and
I'm basically taking three sets
of colors-- or sorry, three
colors, two sets of them
and using a starting
value and ending value.
So, I'm just starting
with 2, 3, 3,
just sort of for
the aesthetic feel.
And then I'm switching
to 1, 2, 2.
So I'm using those
three colors together.
I set the duration
to four seconds,
sunrise takes four
seconds, auto reverses,
and I've already [inaudible]
longer repeatCount here
which is effectively infinity.
And then I just add that
animation to the layer,
and then I can just go ahead
and take that layer and add it
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to any view that that has
a layer already on it.
So you can do that
both on iOS and OS X.
And again, this is
what it looks like.
So, it's pretty cool.
So another sister, I guess,
class of CAGradientLayer
is CAShapeLayer
and this is actually super cool.
This is you are literally
giving it two separate CGPaths
and it animates between them.
It's not-- it's crazy.
And you can also animate
between multiple paths.
Here, I'm just using two and
it's actually a much more fluid
than it appears here
on the screen.
But again, this is
really, really simple.
I literally just
make a CALayer--
I'm sorry, CAShapeLayer
and I set up my path
and I can put all the
vertices here 'cause
that would become a crazy.
But I'd have a starting
path, an ending path.
I create the animation
for the path.
And then, again, I just hit
the duration, the auto reverse,
repeatCount and I
add it to layer.
And it looks like that,
so it's pretty cool.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now, what would be really cool?
How about if we took both
gradient and shape and put them
in the same example, what
would that look like?
I don't even know.
Oh, it will look like this.
So, you've got this crazy--
so what's actually happening
here is the shape layer is
masking the gradient layer.
So, you have all the animation
that's happening on the gradient
but the star, the shape
of the star is actually
clipping the bounds
of the gradient,
so that's awesome.
And literally, all
you need to do
to make this work is you
set all the shape layer code
that I showed you before,
you set that shape layer
as the mask on the gradient.
So here's something else
that you probably
find yourself doing.
You may have some sort of
animation that responds
to user interaction and sort of
the first place a lot people go
with this is that they
actually update the animation
as the user is dragging.
But it's actually really
computationally expensive
to do it that way.
So instead what you can do is
actually change the time offset
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of the layer itself and that
the subtle thing here is
that there's this protocol
that you might not be familiar
with called CAMediaTiming and
the animations adhere to it
but the layer is also
adhere to it which opens
up a whole range of option.
So, in this example, for
the example you just saw
on the screen, I got two
views, I've got the container
and then the square,
and then the slider
to move and back and forth.
And I initially set the
speed of the layer to zero.
And, you know, a lot of these
details I think you're probably
familiar with, so I'm not going
to spend too much time on them.
But I have a BezierPath
which is just a circle.
And-- So the calculation
or the pace sets the speeds
to a quarter of a second
and then add that animation
to the square, the layer.
And then I have this slider
as I'm moving back and forth.
I change the time
offset of the layer
and that's totally responsive,
really super efficient,
so that's the way to do that.
All right, let's keep moving.
Oh yeah, here's [inaudible]
again in case you forgot.
So, here you go.
OK, let's move on.
So, we're going to
look at Core Data.
So Core Data, of course, is
the framework that's available
for both iOS and OS
X developers as a way
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to persist your data
between launches.
And here's just a really quick
overview for those of you
that aren't familiar
with the main classes.
Your Data Stored and
Persistent Store, you access it
through a Persistent
Store Coordinator
and then you fetch objects
into this ManagedObjectContext.
And those ManagedObjects then
kind of like living your app
and populate views,
that sort of thing.
So there's ManagedObject,
ManagedObjectContext,
and Fetch request.
Fetch request is the thing
that's pulling those things
from the database.
But the thing that people kind
of struggle in and actually
in this week in the lab,
[inaudible] a lot is
people don't quite know how
to do backgrounding
operations and it turns
out it's really, really easy.
There's new API added
as far back as iOS 5
in Lion that's been available,
but not everybody has
taken advantage of.
So I just want to mention,
when you create a
ManagedObjectContext,
you can specify that you want
the PrivateQueueConcurrencyType
and this is awesome because
basically what it means is you
get backgrounding
almost for free.
So what happens is you
create this context
with the
NSPrivateQueueConcurrencyType.
You say performBlock with
just any work you want to do
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and you don't even have
to create the queue
that does the work on it.
You don't have to
create the thread.
You just say, "Go do this,
I don't care what happens.
Let me know when you're
done and we'll move on."
So it's super, super easy.
Here's an example.
I mean it's almost
[inaudible] to set it up.
And then with concurrency type,
PrivateQueueConcurrencyType,
I do some work and I
save, it feels great.
And a few other quick
hits Core Data here.
When you're fetching, again in
the labs this week, a lot of saw
that people didn't know about a
lot of this propertiesToFetch.
If you're fetching stuff
from Core Data and you want
to be fast, just fetch
the stuff you need.
So just say propertiesToFetch
on name and phone number.
You can get back
just a dictionary.
If you don't need
the whole object,
you can get back
just the objects ID
and sometimes maybe
just want the account.
You can also do fetchBatchSize
which is awesome.
So if you have like people came
in the labs and they're like,
"Well, we've-- I have
four million records."
It's like, "Well, no
wonder, your app is slow.
You're launching, you know,
four million records on launch."
So just set Batch Size and then
as you'll initially fetch a
hundred and then as you kind
of run through that array,
it will go and fetch more.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And also if you're doing
cross relationship fetching,
you actually want to say,
"Hey, during this batch,
I'm actually going
to need the artist.
I'm going to meet the catalog.
Go ahead and fetch that for me."
And there was a really fantastic
talk yesterday in Nob Hill.
I definitely recommend
checking the video
if you're using Core Data.
Even if you think you're doing
the right thing, trust me,
there are some pretty
amazing stuff in there.
And one last thing,
I don't know how many
of you are actually
familiar with this,
but they're built-in
store types in Core Data
and most people you SQLite,
but if you actually have
a different data format
that you need but you want all
the really nice conveniences a
Core Data, there's a class
for NSIncrementalStore
which you can subclass
and actually implement
your own storage type.
So, that's there, OK.
So, we have a couple
of iOS specific
and AppKit specific tips.
But first, who here has
learned something already?
OK. Wow, all right.
Has anyone not learned
something?
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
OK, yeah, because I was going
to call you on the pig face one.
Pretty sure, I didn't
know that, so-- OK.
So I guess then a few bonus tips
since apparently you've
covered everybody.
UIKit, so this is-- this
is one of these things
where I think most
people know about it
but because it just
came out in iOS 6,
I think maybe not
everybody is really using it.
So UICollectionView is
really, really awesome class
that was added in
iOS 6 that allows you
to do pretty incredibly
complex layouts.
And out-of-the box, you just--
it's basically like
a grid view for free.
So it's like a home
screen for free just
by creating one of these things.
And we actually use it in the
WWDC App that you see here.
So this whole grid
view is actually build
with UICollectionView and
we use a custom layout
and the custom layouts are
actually really straightforward
to do.
So something-- you know, a
lot of times when people run
across a new class,
they've got existing code
and they're thinking, "But--
yeah, but I don't want the API.
I'm going to have to sit
there and figure out.
And then I've got like not
working what I'm already
working on."
But here's the great news
about UICollectionView,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
the API is incredibly
similar to UITableView.
So you-- these are really
just the methods you need,
numberOfSections
InCollectionView,
and I'm just returning my--
the count, and
numberOfItemsInSection,
so it's just like TableView.
And then I can just
return the view I want.
So I'm saying, OK-- and this
is actually [inaudible] code
from the WWDC App that I've
cleaned up a little bit,
but this is actually
what we're doing.
So we pull sessions
from a section.
We get that particular
session object.
We dequeue the cell just like
you would do in TableView.
And then we set the session
and return self, that's it,
and it shows up in the screen.
The real work that's done in
the app is the custom layout.
And it's a little bit more
in-depth, but you can do it.
And of course, with
Mavericks, you know,
being announced this week,
we think we're going to get--
you know, a lot of people are
kind of like, "Hey, you know,
this iOS thing is really cool
but I can actually be making Mac
apps too and be really awesome."
So one thing to know is if in
the past you're used to working
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with UITableView and then
you were thinking, "Well,
I'd like [inaudible] Mac app
but I don't really
know what that's like,"
one thing you should know is
that in Lion we added this
version of NSTableView
that actually use views
just like UITableView.
So all that stuff that--
all those mechanisms that you're
familiar with from UITableView,
just doing arbitrary
layout in interface builder
and just returning entire
views, it's actually--
you know, it's X now,
so you can do it.
And the same people that worked
on UITableView or NSTableView,
so you can imagine that it
works pretty much the same.
And so, you get all that
hardware accelerated stuff.
You get the animation.
Here are some of the
animations facts you can do.
And you can actually add
Core Animation stuff.
So if you for some reason wanted
a TableView of shapes, clipping,
gradients, or something
like that,
you could actually do that.
And again, actually this
is incredibly similar
to the CollectionView example,
numberOfRowsInTableView.
You turn a row for the view
and I just can change whatever
properties I want before it
gets displayed.
And the one thing I want to
point out here, just calling
out a little bit separately,
is there's an existing
class that's NSTableCellView
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
which you can use generically.
You can just use as it is
or you can subclass it,
or you can just whatever
view you want.
So if you have-- I have an MS--
MyGridView and I've just
completely implement
that from scratch.
So it's just something
I was using elsewhere
but I'm including the table.
So if you have a lot
of flexibility there.
All right.
So, was that-- that
was pretty fast,
but I think we hit everybody.
So we got-- pretty much
everybody learned something.
So with all this stuff, if
you have questions on any
of this stuff, you can talk to
our good friend Dave DeLong.
He's the App Frameworks and
Developer Tools of Evangelist.
There's documentation and forms,
in case somehow you
haven't heard of those yet.
And do checkout those other
sessions 'cause they're really,
really good.
There's Designing Code
for Performance on video
and Core Data Performance
Optimization
for Debugging, and that is it.
Thank you very much.
[Applause]
[ Silence ]