Transcript
>> Blaine Garst: Let's see.
Oh yeah, that's my name, Blaine Garst.
I'm Blaine Garst.
On my business card it says "Wizard of Runtimes," and so on
the slides there's this little slot where you're supposed
to put your title, and so I just
kind of copy/pasted it there.
So, what does Wizard of Runtimes mean?
Well, I don't know.
I work on the runtimes for the
Objective-C language, primarily.
And so, the runtimes is where all the coding happens.
And since I'm a programmer just like you
guys, that's where I get to do my programming.
So, my programming helps you guys do your programming.
So, what's going to happen today is we're going to talk
about Objective-C, and about how you folks can learn more
about the language and some of
the things behind the language,
some of the things about the frameworks
underneath it or above it,
Cocoa Touch, and learning how to use it effectively.
So, the first thing we need to fix with the slide
is we're going to talk about iOS, not iPhone OS.
In particular, the iOS platform applies
to the iPad, the iPhone, the iPod touch.
You know, this is the description for
what this session is supposed to cover.
And first of all, if we could raise the lights a
little bit, I'd like to get a feel for among you folks,
how many of you have yet to ship your first app?
Wow, OK. How many here have shipped maybe only 2 apps?
And I assume the rest of you might actually be a little
more familiar with Objective-C than some of these folks.
Thanks, that's enough for the lights.
So, let me tell you what's going to happen.
We're going to take a tour, a little bit of a tour
through Objective-C and some of the most effective ways
to use Objective-C on Cocoa Touch, and I'm your tour guide.
So, as your tour guide, let me
introduce myself a little bit more.
I've been programming since 1973.
I joined NeXT.
[ Applause ]
I joined NeXT Computer in 1990, and I had
a little bit of experience at that point
and I started doing things with my practice and experience.
I got to take some patterns of programming that
I really enjoy and I put them into the language,
so that my techniques of programming
became standard practice.
In particular, I helped to add
protocols to the Objective-C language.
[ Applause ]
>> This solved-- when adopted by Java, and
they were pretty much copy/pasted into Java.
I have some quotes from Gosling on that.
That solved the client-server problem for like servers and
stuff 'cause I could have this abstract design and stuff.
And so, I've been doing things like this ever since.
And so today, you're getting a tour by the tour guide.
You know, I might look like a horse because what I speak
about in Objective-C is straight from the horse's mouth.
It doesn't get any better than this.
So, let's get started.
The iPad, the iPhone, these are awesome things to program.
There is so much fun.
It's so exciting to have all of this
code out there that you can really play
with them, make things happen on these devices.
These devices are just awesome.
To make things happen on these
devices, you need to learn Objective-C.
It is the core, the center of how we make things happen,
how you make GUI in particular
happen, graphical user interfaces.
How you make Cocoa Touch do what you want to do.
There are other languages out there and my presumption
is that you know at least one of these other languages
because I'm not going to teach you Objective-C necessarily.
I'm going to teach you differences between what you
know and what we do here-- what we do with Objective-C.
In particular, when you think about
different languages, the first thing you think
about is, well, you get syntax differences.
They've got different kinds of control flow operator, you
know, operators and control flow primitives and things.
In particular, some languages have exceptions.
Some languages have these things called
closures, which for Objective-C, we call blocks.
And if you know these patterns, what you
really need to know is how do I do this pattern
in this new language or this different language?
But beyond just the syntax, there's a lot of
other stuff that has to go on when you do--
when you really need to make things happen.
You've got-- you know, how do you do math?
Do you have infinite precision numbers?
Nah, we usually have integers and
floats, right, in some languages though.
But, you know, we have strings at different levels.
We have C strings, we've got these NSStrings.
There are structures versus objects for aggregating data.
If you have objects, you have different
inheritance models, you know, the list goes on.
By the end of the list, when you talk about platform
things, Memory Management is very much tied to the platform
and languages are often tied to a platform.
And so, you have to learn more about the platform.
It's sort of beyond the language and you definitely
need to learn about Memory Management on the iPhone.
I hear this is a little bit perplexing to some folks,
and we're going to talk about that in particular.
So, to summarize what I just said, I'm going to try to
map and go what you know in terms of familiar concepts
with just a little bit of terminology difference
and clear a little bit of syntax difference.
We're going to introduce and talk about Objective-C sort
of uncommon ideas, things that have not quite made it
to the mainstream, yet unless you
consider Objective-C mainstream.
It is, I think, the number 10 most popular
language now, at least by some definition.
So these are the things we're going
to talk about to help you learn how
to use our kits, UIKit, et cetera, to advantage.
In particular, I want to talk a little
bit about what I consider be a pattern.
Now, there are books out there, design patterns and stuff.
And don't get worried, I'm not a boost kind of guy, but
we will talk about patterns that make sense in terms
of how we design things and how you have to use those.
So, that's what we're going to try to cover today.
Again, Objective-C is at the core of
how you program the iPad, the iTouch--
or the iPad, the iPhone, and the iPod touch.
There are two other languages though, that you
interoperate with all the time, and those are C and C++.
Now, the first topic I want to talk
about is this thing called blocks.
Blocks has been added to the C language.
And through this thing called language inheritance,
you get to use blocks also from Objective-C,
which is a pure superset of C and C++ as
well because that's what our compilers do.
And what blocks allow you to do is program
from any language you want and stick blocks
that use your programming language
anywhere that a block is asked for.
So, it's sort of a glue facility
of cross-languages to some extent.
So, let's talk about blocks.
I understand that this thing about multitasking is important
to you guys, and so the background task identifier,
if you want to learn how to totally do background
tasking on the iPhone, you might have to learn this API.
It's got this block thing at the end, this
void caret handler thing at the very end.
And so, actually it got talked about earlier in the
week, so let's pick a different thing to talk about.
There's quite a lot to choose from here.
In fact, there's over a hundred
APIs in iPhone OS 4 that use blocks,
so I'm not going to pretend to
go through any of them, honestly.
But this is kind of just a motivation as to, you know,
why you might want to listen through this section.
So, this is what blocks look like for the C language.
We introduce this caret expression kind of syntax to mean
sort of a local function, a local function expression.
You can write a function expression
where you would write other expressions
and you pass them as parameters for the most part.
In this case, what we're doing is we're going to send to
some function called repeat, this little block pattern
that says do a putc on d, presumably 10 times.
And the idea here is that d is going to go along with that.
You know, d is a local variable and you're going to get to
use that within your block as it goes off and does things.
Now, blocks are actually not a very new concept.
That's what they look like in C.
They are called blocks in Ruby and in Smalltalk.
And in fact they were sort of invented in LISP--
in the scheme, actually, somewhere around 1973.
They were called closures in Scheme and
there's a-- there's a lot of interest in this.
In fact, there's a new standard coming
out for C++ and it's called C++0x.
It's in final committee draft or something like that.
And they have a construct called the lambda.
Now a lambda only fits into templates, for example, and
that's the syntax you would use for the closure expression,
but you can't actually use them-- you
can't pass them directly to functions.
They're only useful within templates and they're different.
They're not full closures, they're a little different.
But the idea is coming along and we're happy and proud
to provide to you blocks, you know, on the phone,
as we've had them on Mac OS for a year or so.
So, here's another use of that repeat function, this time
using some Objective-C code where we're just going to,
you know, append some strings to a mutableString.
And the next box tells you how to
implement that repeat function.
And so the syntax we use for blocks
is that of function pointers.
Think function pointers with the caret symbol instead of
the star and you'll understand the syntax of block pointers.
So, they're really block pointers just like we have function
pointers, except to use that caret thing for the syntax.
And to use them, you just call them as if they
were function pointers as I've shown here.
So, they're pretty easy to use, pretty
easy to implement and work around.
And so that's why we use them all over the place.
They're useful, they're fun.
To summarize the syntax, we got a typical spot,
sort of the function pointer return
value slot or the return value specified.
You get some parameters some of the time and you got a body.
In this case, we're returning-- I
don't know, it's a contrived example.
Another-- a thing we did though to make life
easier, is we allow you to use abbreviated syntax.
And so when the compiler sees a return statement,
it knows there has to be a return value.
And so, if there's no return statement in that body, then
it can assume that it's a void, returning a void thing.
But in any case, even if you do return something,
you don't have to specify that return value type.
So, the second line is exactly equivalent to the first line.
So, you don't have to say int, we infer this.
So the same is true, as I just said.
If you don't do a return at all, we assume
void, so you don't have to type void.
And in the special case where you
return void and have no parameters,
you don't have to put the parameter list in either.
And so that's why you kind of see
different syntaxes for these block literals.
And what this do is when a compiler encounters them, it
creates a structure on the stack, which is the block object,
and leaves you a pointer to this structure on the stack.
So, this is both fast and dangerous and so
we have to be a little careful about these.
And we'll talk about that a little bit later.
So, blocks are also objects.
Even though stack-based things, you can send them messages.
Now, there's only a couple of messages that are of
interest, and those are for primarily copy and release.
Because copy says make a perma-- make a-- copy it to the
heap so that it can survive the stack frame of origin.
So what that allows us to do, allows you to do is
write a block expression, pass it off to some API.
And if the API wants to keep a hold of it, pass
that use, it can do a copy on it and preserve it.
And that copy costs a little extra cycles.
They have to alloc-- we have to allocate
memory off the heap and copy it in there.
But sometimes you need to do that and sometimes you don't.
And so for the times you don't, we don't
allocate heap storage for these things.
So, they're very efficient and, yeah, we like that.
We use them in many, many places.
We use them to enumerate collections.
We use them for what I call callback notifications.
There's often I'd like to say with networking code where
you're going to go, you know, fetch URL in chunks, you know,
and every chunk needs to be processed, and so you panned it.
Now you had a block in and every chunk is passed to
your block, and that's a much nicer way to code it.
There's going to be some more talks later this week which
give more examples of the code savings you get to use
by just putting the codes you want in the block and
just handing it off to the API that needs it later.
There's another whole facility
called Grand Central Dispatch.
There're a couple of talks on that.
There's one actually later today.
I'll give references to this.
Where we talked about two things: One is to move code
off the main thread, off the main dispatch queue,
off the main run loop, whatever we call it nowadays.
Because if you try to do too much
work there, then on the Mac,
you get the spinning cursor, on the iPhone you get killed.
So, you don't want to do that.
So, you like-- you want to learn how
to move work off the main thread.
And another thing, GCD is very powerful.
And in general, if you can figure out how to do
things in parallel, GCD is the way to express
that because what GCD does is optimize memory
and battery life and all kinds of things
to make sure you just give enough resources
to get that job done under the circumstances.
And so you just code to GCD queues and the system
kind of takes care of all the thread pooling
and all the other kind of stuff going on.
It's very nice, there're talks later
on, I'll give you a reference to those.
What I showed you on the other
expressions is we capture the variable
and we make a local sort of const copy in that block object.
Sometimes though, you need to mutate the variable.
And so, we actually introduced a new storage
class keyword called under-under Block,
for those cases where you need to pull a
value back from something you sent off.
And I'm not going to talk about
under-under Block here very much.
It's there, it's useful, it's somewhat intuitive, it works,
and if you want to know more, we definitely will talk
about that later to a great degree, on Friday in particular.
So in this case, we're going through a dictionary.
We're given a particular key and
we want to return the value.
I'm sorry, we're given a value and we want to sort
of find the key that was associated with that value,
and so we return the key back to the caller.
So these are the two talks I've referenced.
There's Introducing Blocks and Grand Central Dispatch at
11:30 today, and on Friday we have Advanced Objective-C
and Garbage Collection Techniques, so that's
a little bit more of a Mac and a phone talk.
We cover material for both.
Here's another language construct, the for-in statement.
There's a lot of ways to go through an array.
Most people, we looked at code and many
people are doing this objectAtIndex,
objectAtIndex, objectAtIndex to go through arrays.
Arrays are the lingua franca for collections.
We get arrays back from many, many different APIs.
And going through arrays, we found
that's taking up too many cycles.
So we introduced the language construct for-in that
is backed by a particular protocol which you can adopt
in your codes so that your objects can be-- you can use the
for-in statement on your objects and have them, you know,
rip through whatever kinds of items they might manage.
But in particular, this is a best practice
because this is fast, fastest actually.
This is safest because in the middle of that
iteration, we're actually checking to see
if somebody changed the array underneath you
or changed the dictionary underneath you,
which can generally cause crashes.
And so we throw an exception when we detect a
change so that, you know, at least you don't crash.
You get to figure out what-- you
know, how that exception happens.
So that's, you know, that's a case
of a good practice that we pulled
into the language, and that's the kind of thing we do.
We try to make your job easier and
better and more concise and clear
and all that, all in one little language construct.
People ask me though, how do we get
two values out of the for-in statement?
I couldn't figure out how.
Well, I didn't want to do it the way I figured it out.
We had a better way, and the better way is blocks.
So, if you need more than one value at a time out of an
array or a dictionary, we've added block enumeration APIs
and these are now the fastest way
to get more than one value out.
So, in the case of arrays, I've
illustrated how to get an array reversed
with the index, and that's the fastest way to do it.
And then dictionaries, you often want to
get the key and the value at the same time,
and so this is the fastest way to do that.
These are also safe and are also extensible
because, I'll show how to extend them later.
So anyway, this is best practice.
Let's go back to the phone in these three languages.
It turns out, there's another language on our system.
It's called Objective-C++.
And just as we add sort of an object layer
on top of C in the Objective-C language,
we add that same different object layer on top of
C++ which has its own object, ideas about objects.
And so, let me tell you about Objective-C++ for just a
minute, because if you already have a pile of C++ code,
what you need to know is how to
get the GUI to respond to it.
And so, what you typically do is you write a few files
in Objective C++ and they can talk to your C++ code
and they can talk to the GUI code and, well, I don't
know, you can use Objective C++ for all your C++ code.
And so in this example, it's again contrived.
You signal that it's an Objective-C++ file by the .mm
and a few other variations extension,
and you sort of get to mix and match.
You can mix and match declarations,
instance variables, member variables.
I haven't gotten the terminology slide yet.
So, in this case, I have a C++ class called My Engine
and you can put a reference to your widget in there.
Equivalently, you can have your widget
class and put your engine in there.
So, that's pretty useful.
So, even in Objective-C methods, you
can use the throw statement from C++.
Objective-C has it's own @throw, @catch and @finally,
but the exceptions underneath, the runtime implementation
of them is the same across both of the languages.
And so you can throw from C++ and @catch
from Objective-C, which just works.
The thing that you can't do is you can't sort of
subclass a C++ class in Objective-C or vice versa.
You know, the object models are distinct.
So, you don't get operator overloading in
Objective-C and you don't get selectors in C++.
So, it's sort of a marriage of
convenience perhaps, I don't know.
Let's go on a little bit.
So, Objective-C has its own terminology for common
concepts, and it's hard to present this any other way.
I mean, in Java C++, people talk about member variables.
We talk about instance variables or ivars.
A member function is a method or an
instance method perhaps, or a dash method.
And unlike C++ and Java, they're
always virtual and they're never final.
So, if you like those patterns, just do it by convention
and you're just not going to get compiler support for that.
A static method is different in Objective-C.
In Objective-C, we sort of have a meta-class,
and that the class actually is an object itself.
You can have messages and you can do inheritance in your
plus methods, so you can call super within a plus method,
which is kind of new, a little bit different.
But still, the idea of having a
class method is not totally new,
and so we have to have a terminology thing here
even though the behavior is slightly different.
We have no equivalent to static variable as of yet at least.
So, we just use globals, it works.
What is called an interface, in other languages
it's called a protocol, in Objective-C even though--
we wanted to call them @interface, but as you can see, what
we call a class, we introduced a class using @interface,
so we couldn't use the @interface keyword
that long ago, but other people pick that up.
There is no operator new.
There are no stack objects.
Everything is allocated off the heap
using an alloc method generally,
or we have these things called convenience
constructors, other plus methods can build you things.
I gave you an example already that NSMutableString string.
That string is a plus method that did a sort of a
MutableString alloc init autorelease and return the result.
And finally, we have no explicit destructors.
We have something called the dealloc method.
But unlike destructors, you should
never call the dealloc method yourself.
The dealloc method is called by release;
when release figures out that the last
release has happened, it calls dealloc.
So, don't treat deallocs like destructors.
You will get into a lot of trouble
really quick if you try that.
So, let's do a little bit of review.
We have single inheritance of instance behavior.
So, we have NSObject, it's a got a hash function.
So, we're going to have an airplane and an animal.
We're going to have a fish and a
bird and we're going to have a duck.
And what the language allows is
multiple inheritance of abstract methods,
and so in this case we have a swimmer
that has one method called swim.
We have a flyer and a machine, and as you
can see, the-- I'll see which one is it.
One of these-- duck that multiply inherits
both swimmer and flyer effectively,
and so this is the syntax we use to specify that.
Duck inherits from bird and implements
the swimmer and the flyer protocols.
There's something new though.
Let's pretend that Apple provided animal and bird.
As I said, there was a hash method, there's also
an isEqual method, isEqual is often overridden.
There's a method on NSObject called self.
And I've dimmed out self to sort of indicate
that you really never re-implement that method.
You just inherit the implementation from NSObject.
And so as you get deeper in the class hierarchy, you
get more and more behavior, more and more methods show
up like you got a parents method out of
animal and out of bird, you get a fly method.
And sometimes though-- well, and this is good.
This is what most languages do.
In your application, let's say
you're trying to build a dragon.
And what would be nice, because you're going to animate
these things, it would be nice if you could ask--
you're going to animate lots of objects
including the Apple provided ones and yours.
It would be really nice, though, if you
could just ask, is this object mythical?
Is this Apple provided object a mythical animal?
So, you'd like to add the isMythical method
on to Apple's animal and you can do this.
You do this with something called a category.
Now category is never-- the term category
is never-- it's not in the language.
It's just this funny syntax, and this is the funny syntax.
You declare an extension.
Here I labeled it MythicalExtra and you name a
method, and you promise to implement this somewhere.
And so this is what the implementation would look like.
For animal, it's not mythical, return no.
But in your class, in your dragon class, you also
implement isMythical, and in this case you return yes.
Now notice that bird is going to inherit
animal's implementation so you can--
you know if the bird gets asked, are you mythical?
It's going to inherit the implementation
on animal that you provided in your code.
So, let me talk about categories a little bit more.
So the add behavior to any class; use this judiciously.
I would not recommend just using isMythical here
because you might borrow somebody else's code
or Apple might insert an isMythical method or something.
And so, when you choose method names to extend, make sure
they're really unique because we have a kind of a bug
and we can get a little bit of collisions on these names.
Use them judiciously.
You can extend NSObject but it's not really recommended.
We don't really want a thousand methods on NSObject,
it slows the whole system down a little bit.
So use them where you need to, but
it's a very powerful technique.
They act like normal methods.
You can call super from them, in fact.
And with a little bit of code, you can also add
data to sort of have kind of like a mix in model.
And the way you add data with categories, this thing we call
associative references, and we'll talk about that on Friday.
It's API, and I don't want to get in to too much API here.
You can also use categories to split your implementation
of a class across several files, because technically,
as long as you're within an app or a
framework, you actually have access
to the private instance variables,
again, a little dangerous here.
We don't allow that across frameworks, though.
These categories are very useful.
Let's talk about Memory Management.
So why? Well, if you don't do it
well, you're going to crash.
Memory Management is about keeping objects
around so you can use them when you need them.
And if you don't keep them around, you're going to crash.
On the other hand, if you keep them around forever,
your app gets more and more memory, it gets sluggish,
it gets sluggish, and eventually that's
going to cause it to crash in a way itself.
And so, Memory Management means using just
the right amount of memory and no more.
So, the Cocoa Touch system that you use,
the retain, release, autorelease thing,
was designed for use on a 8-megabyte
system, like 20 years ago.
And, you know, we had to be very memory efficient
back then, and that's also true on the phone.
So, you know, some things change
and some things don't change.
So, it's been around for a while.
So Memory Management, unfortunately, the design of
it starts at-- I mean, it starts at the design phase.
If you just go build an app and you throw retains around
like crazy and then you have to come back and clean it up,
you can be in trouble because you have to think
through your object patterns at the design phase,
and you learn that on your second app probably.
So, the way you design it is you design
object ownership as a directed acyclic graph.
And the ownership of objects comes
from a very simple pattern,
and that is we have few methods that transfer ownership.
Alloc and init transfer ownership
of an object to their receiver.
A copy method does the same thing and there
are a few plus new APIs that also do that.
But otherwise, APIs do not transfer ownership.
You just kind of use them because the objects are around.
And as you saw in the-- if you did, I hope you did.
As you saw in Monday's afternoon talk, the static-- LLVM
Static Analyzer can help you with your retains and releases
by showing you where you got it
wrong, and that's a very cool tool.
The Instrument application can also show you
where you got leaks, and that also was demo'd.
In particular the heap shot command within the memory,
within the allocation instrument can help you detect
unused memory that's just kind of hanging around.
So, let's talk about that directed
acyclic graph a little bit.
So, here's one of them, and it's kind of like a lattice.
You know, pointers just keep pointing down.
And I've illustrated the reference counts, you
know, the number of retains in each object this way.
And let's say that these are all of
the references on the system right now.
So, what happens when that top reference to part of
that graph goes way, the top object loses its ref count
to zero then it lets go of its things on down.
Now, did everybody see the pattern go down?
Let's try that again.
When we let go of that top reference, that top
object goes to zero, it lets go of things it owns.
They let go of what they own.
They let go of what they own, et cetera.
And once you have retain count zero object,
it gets reclaimed and so your graph goes way.
This is what you want to happen.
If you accidentally set up a back pointer, an up pointer
that is retained, then what happens when you let go
of that top reference is the top node
goes from ref count 2 to ref count 1.
It sticks around forever, not what you want.
I think it's obvious what happens if you
fail to do a retain count of an object
and it goes away prematurely, that's also bad.
So, the simple rules to make Memory Management
work well for you are that at the design phase
for every instance variable you decide,
do I retain this one or do I not?
Is it an up pointer?
So, the general pattern is you
retain your instance variables.
Only those up links get non-retained.
And when you go to do assignments, you have to
release the old value on retain instance variables,
and send the retain message to the new
value coming in unless the new value came
from like one of those methods, init, or copy or new.
Finally, sometimes if you're asked to provide a
result and you have to create a result on the fly,
you stick it in the autorelease pool if you don't keep
it yourself, and so that your caller just seize it
and it will go away after a little bit of time.
Let me explain how autorelease pools work.
So at the bottom of your stack, there's
a little bit of code that's going
to get an event or something and call your code.
It's going to call the process event.
So, at the beginning, we created-- well, we have a
stack with some local variables and so we create a pool
and we create-- and we get an event from somewhere.
Now, in all likelihood, the event is also held in
that autorelease pool, but I'm not illustrating that.
And so we start calling process.
And let's say process needs a new date.
It's going to call NSDate date and get
some value out of that and compute.
We passed the event on up the stack.
So inside NSDate, there's some
code that looks a lot like this.
This is the alloc init autorelease pattern.
That's very common.
You guys should probably learn that one as well.
So, at the very beginning, at the alloc init time,
what happens is sort of the stack holds a reference,
a retain count reference to the object D,
that date, and then we send autorelease to it.
And what that does is it transfers ownership down
into the autorelease pool, which is secretly around.
You know, it's just there.
When the date routine returns, you know, D
is returned on the stack, it gets processed
and used, you know, it gets the value out of it.
And when that frame goes away, the autorelease
pool is left with the reference to that date.
It's still hanging around even
though nobody knows about it anymore.
But eventually the pool is drained, which is how we get rid
of the objects within a pool and get rid of the pool itself.
And so, the pool goes away and everything within
it goes away and that data object goes away
and there's no memory loss, and so
that's how autorelease pools work.
You can actually create them and use them yourself
when you know you're going to be creating a lot
of objects, a lot of autorelease objects.
You can create a pool and then drain it yourself, and
that's a well understood Memory Management technique
that you use when tuning for performance.
Let's talk about accessors.
In Cocoa, we have had this pattern for 18 years of
balance and setBalance as the way we named our accessors.
You have a backing instance variable called int balance,
and in the implementation you implement these methods.
There's just a lot of typing of that balance word, right?
So, to kind of make this simpler, what we
introduced was something called properties.
And so to replace that code I just
showed you, this is what you need to do.
You say @property int balance.
And then in your implementation, you say @synthesize
balance, and because we now have the same runtime running
in the Simulator, as you have on
the iPhone, we get to make use
of this Objective-C 2 feature such
if that's all you have to do.
The compiler will synthesize the
instance variable in your class
and it will synthesize the implementations
of that setter and getter.
In fact, though, we noticed, well,
why do even need the @synthesize?
And so, in Xcode 4, in the new
LLVM compiler that comes with it--
[ Applause ]
-- it's on by default.
So, let's talk a little bit more.
To get to that new facility though, you
have to pass a special flag to the compiler.
It's there but it's not quite integrated
in the IDE the way we would like it to be.
It will be though.
So, let's talk about properties
a little bit more specifically.
Properties have attribute, so these things in parenthesis.
In this case, we're going to say perhaps
balance was a read-only in customobject,
and in a subclass of customobject called supercustom,
we want to make it read-write, that is allowed.
Otherwise, whatever attribute you see sticks.
It's an unchangeable property of
the property unchangeable attribute.
Let's talk about what those all are about.
So, if you don't like our names, if you don't like
set and if you like get or whatever, you can actually,
in that parenthesized section, you know,
provide your own custom method names.
The other-- the other thing you could do as an attribute
is particular if you're talking about an object property,
is you have to tell the compiler whether it's a
retained object, whether it's simply assigned.
Assigned is sort of a synonym for non-retained,
at least in the retain-release world.
And the other option, the key option, is copy.
Well, we'll get to copyable-- mutable
copy kinds of things later.
But it's very important-- and copy
implies retain, by the way.
So, that's how you get values into your object, you know,
but you can pass a mutable string in because it's going
to be copy that we copied into
an immutable string and stored.
Nonatomic is a keyword that sort of means single-threaded.
It's kind of performance.
There are some slight safety issues with it
but it's very prevalent on the iPhone, on iOS.
But it's generally considered harmless.
We'd prefer that you not use it though
because as dispatch queues and things go on,
things are becoming more multithreaded all the time.
Finally, I already talked about read-only and read-write.
The idea with that property is you don't have to
trust the compiler to do any of the work at all.
You can use an app property and fully implement it.
You can have your secretBalance, you
can write your setter and getter.
In this case, maybe you had, you know, a different
instance variable than something called balance.
And so I illustrated that.
And that pattern is common enough though
that we actually support that in the compiler
by simply saying @synthesize balance=secretBalance.
And if you didn't even provide
secretBalance, you could do that also
and the compiler would synthesize
a secretBalance instance variable.
So it's-- use it you know as much as you want, use
it for everything, use it for some other things.
Finally, if you're going to be using that @property by
default, there are some rare cases where you don't want
to provide an implementation at all because you know how to
use forwarding, because there's another hook you can use.
And in those cases, you have to use @dynamic
or you will be required to use @dynamic
to tell the compiler to not synthesize things.
So, that's a keyword that's going to get
a little more use, I think, in the future.
Again, advanced garbage collection, Advanced Objective-C
and Garbage Collection talk is where
you're going to learn about that.
Now, I cheated a little bit.
I didn't talk about properties of objects.
This is a pattern you have to write,
would have to write yourself in order
to implement a correct property object
attribute, I'm sorry, correct object property.
In particular, you need to synchronize, you need to make
sure that 2 threads aren't trying to set at the same time
and one of them gets half the result and the other
one doesn't, or a getter is trying to come in
and give a value that's being changed,
being released underneath it.
And so, it's actually kind of complicated.
And so, we actually want you to
use that synthesize, wants you to--
you have the compiler in runtime
do the hard work for you on this.
And in particular, you do need to write a little piece
of code in the dealloc method to get rid of that object.
So, here you can just send title the
release message, which is typical.
I also showed what we call our .syntax.
Self.title = nil is some shorthand
for saying set title to nil.
The compiler just turns that self.title
into self set title to nil.
And that's-- the .syntax works,
you know, everywhere pretty much.
And-- but it's just shorthand for
sending Objective-C messages around.
We don't really do-- the compiler really doesn't,
you know, spit out the code to do it in line.
It's just-- it's just a-- almost a macro for
calling-- calling the message explicitly.
So, let me talk a little bit more about Cocoa patterns.
So, selectors are kind of fun, they're
not really in any other language.
Selectors are data structures that
represent sort of the slot name.
There are some API's you can get to,
to get the actual string that's used.
It's foo: bar: whatever, at the moment.
They're not really too interesting.
The id object type, that was the original object type
and the only object type when Objective-C was invented.
It allows any message to be sent to it, without warning, by
the compiler, even ones that aren't going to be implemented.
And we have invented or it was invented, this method called
respondsToSelector, and so in this case we have syntax
for naming a selector on the fly called @selector here.
We're going to ask, does object
respond to the selector fred?
And if so, we're going to send fred to that object.
Now that's kind of squirrelly you might think,
except within UIKit we use it all the time.
Let me show you where.
We use it for delegates.
You know, an Interface Builder where you hook up
a delegate to a control, this is what's going on.
You implement a particular method that you
want done at a particular piece of time.
I pulled this one out of the action sheet thing.
So, suppose you needed to overwrite and do something special
when the willPresentActionSheet message would come up.
And so, you implement just that method and,
you know somewhere you set the delegate.
And normally, you kind of do that in Interface
Builder, but you can do it by hand also.
And again, the .delegate is our .syntax for
saying UIActionSheet setDelegate to self.
So, this is your part on how to do delegation.
Inside-- or not inside, but UIKit actually declares a
set of methods as optional methods within a protocol.
Optional is not in other languages.
Optional says these are sometimes implemented.
This is the syntax for them.
And so, UIActionSheet declares its
delegate as implementing this protocol.
And so when you set the delegate,
you know, your class-- let's back up.
Your class implements UIActionSheetDelegate.
And so you get type safety when
you do that setDelegate method.
And inside UIKit, when it comes time to ask to present
that sheet, it goes respondsToSelector, you know,
whatever that meant that was, willPresentActionSheet.
And if your object implements it,
then it will go send that to you.
Or in other time, it's going to say
didPresentActionSheet and it goes respondsToSelector
and you don't implement that, so
it says ah, don't bother, skip it.
And so, respondsToSelector is a very powerful mechanism
to, you know, add optional behavior to things.
And it simplifies your life because you could put a lot
of code in the delegate and not have to do subclassing
and figure out how to do subclassing properly.
So it's a pattern that we use a lot.
Target action uses selectors all the time also.
Let's talk about class clusters.
A class cluster is sort of an abstract class, like NSString,
then that's all you want to know about strings is the things
in NSString itself, even though under the covers what
we do is we actually have several implementations.
They're concrete secret private
implementations and you don't care,
except if you know how to build a string yourself,
we tell you how to do that by implementing
sort of a key method in the abstract class.
So, we don't typically subclass
NSString to add behavior to it.
You know, you don't tell it to go do other
things too much, we use categories for that.
So there're categories for, say, open this
string as a file rather than subclassing it,
the sting to be a special file kind of thing.
So categories let's you add behavior to things
like even NSString, and Apple does that.
And you get to subclass primarily
for representational reasons.
There is, and we hear about-- you see in the
documentation this thing called property lists.
And property lists are value classes, including collections.
So we have strings and data, we have
NSNumbers and we have dictionaries and dates.
And so those are the property list classes.
They are easily transcribed and onto disc or
into HTML or, you know, many different formats.
And the key thing about them is they're immutable.
They're a value class.
You can use them freely across all those threads
that dispatch is offering you because, you know,
there's not going to be no contention on them.
Another pattern-- or this isn't really a
pattern, this is just part of the system.
A pattern we have is sort of our mutable value pattern.
Several of those classes, plus a couple of others and not
all of them, we have this abstract layer of immutability.
Strings and arrays, you can't change.
Data, you can't change.
And so we have for each one of them an inheritance,
and we have a mutable version of
them which you can change obviously.
So when we designed these, we said we want to have a
mutableCopy method, and clearly a mutableCopy method
when passed to a mutableString
should give you a mutableString back.
And similarly, if you sent mutableCopy to an NSString,
you should get a mutable version back out of it.
So, that led us to conclude that when
you send copy to an NSDictionary,
you should get an immutable dictionary out of it.
But surprisingly, when you send copy to a mutable
dictionary, you get an immutable value out of it.
That's just the way we do things.
It's a little surprising, you need to know this.
We have protocols for both of those.
And so you see the protocols adopted.
NSObject for example does not implement the
copying protocol, so your objects do not have
to implement copying although NSObject
does actually participate
and actually does implement copy just
as a helper for those classes that do.
So, I talked about the terminology for common concepts.
I talked about our most important uncommon ideas,
you know, blocks and properties, categories.
I touched on some of the other little-- little things
that are different about our language and how we use it.
And finally, we talked about patterns a little bit.
So, the related sessions of interest are Introducing
Blocks and Grand Central Dispatch where you learn how
to move work off of your queue, that's later today at 11:30.
API design for Cocoa and Cocoa Touch, we
have a review committee for APIs inside Apple
to make sure they come out looking just right.
And API design is hard.
And so, Ali Ozer is going to give
this talk on Thursday at 4:30.
I highly recommend it.
Ali is just the best guy for this.
Advanced Objective-C and Garbage
Collection Techniques is going to be given
by my colleague, Greg Parker, on Friday at 11:30.
We'll talk about how blocks really get copied to the
heap and, you know, some of the fun stuff that goes on.
And for more information, you can contact your developer,
our developer tools evangelist, Michael Jurewitz.
He calls me Blainecus
so I call him Michaelopolis.