2

I am having problem understanding part of the function of "selectors", as described in Apple's guide. I've bolded the parts where I am getting confused:

In Objective-C, selector has two meanings. It can be used to refer simply to the name of a method when it’s used in a source-code message to an object. It also, though, refers to the unique identifier that replaces the name when the source code is compiled. Compiled selectors are of type SEL. All methods with the same name have the same selector. You can use a selector to invoke a method on an object—this provides the basis for the implementation of the target-action design pattern in Cocoa.

Methods and Selectors For efficiency, full ASCII names are not used as method selectors in compiled code. Instead, the compiler writes each method name into a table, then pairs the name with a unique identifier that represents the method at runtime. The runtime system makes sure each identifier is unique: No two selectors are the same, and all methods with the same name have the same selector.

Can anyone explain these bits? Additionally, if different classes have methods with the same name, will they also have the same selector?

jscs
  • 63,694
  • 13
  • 151
  • 195
S.J
  • 3,063
  • 3
  • 33
  • 66

4 Answers4

16

All selectors are uniqued -- both at compile time and, dynamically, at runtime through sel_getUid() or the preferred sel_registerName() (the latter being largely preferred, the former still around for historical reasons) -- for speed.

Back story: to call a method, the runtime needs a selector that identifies what is to be called and an object that it will be called on. This is why every single method call in Objective-C has two parameters: the obvious and well known self and the invisible, implied, parameter _cmd. _cmd is the SEL of the method currently executing. That is, you can paste this code into any method to see the name -- the selector -- of the currently executing method:

NSLog(@"%@", NSStringFromSelector(_cmd));

Note that _cmd is not a global; it really is an argument to your method. See below.

By uniquing the selectors, all selector based operations are implemented using pointer equality tests instead of string processing or any pointer de-referencing at all.

In particular, every single time you make a method call:

[someObject doSomething: toThis withOptions: flags]; // calls SEL doSomething:withOptions:

The compiler generates this code (or a very closely related variant):

objc_msgSend(someObject, @selector(doSomething:withOptions:), toThis, flags);

The very first thing objc_msgSend() does is check to see if someObject is nil and short-circuit if it is (nil-eats-message). The next (ignoring tagged pointers) is to look up the selector in someObjects class (the isa pointer, in fact), find the implementation, and call it (using a tail call optimization).

That find the implementation thing has to be fast and to make it really fast, you want the key to finding the implementation of the method to be as fast and stable as possible. To do that, you want the key to be directly usable and globally unique to the process.

Thus, the selectors are uniqued.

That it also happens to save memory is an fantastic benefit, but the messenger would use more memory than it does today if messenging could be made 2x faster (but not 10x for 2x -- or even 2x memory for 2x speed -- while speed is critical, memory use is also critical, certainly).

If you really want to dive deep on how objc_msgSend() works, I wrote a bit of a guide. Note that it is slightly out of date as it was written before tagged pointers, blocks-as-implementation, and ARC were disclosed. I should update the articles.

Cœur
  • 37,241
  • 25
  • 195
  • 267
bbum
  • 162,346
  • 23
  • 271
  • 359
  • WOW what a fantastic replay, thanks a lot. Please can you give me some tips how I can improve my skills like you. – S.J Jun 16 '12 at 07:33
  • You are welcome; as for how to improve? Practice. I've been doing this for quite a while. :) – bbum Jun 16 '12 at 07:56
5

Yes. Classes do share selectors.

I can give an example from the source code objc-sel.mm, but when you use sel_registerUid() (used behind the scenes in @selector()), It copies the input string into an internal buffer (if the string hasn't been registered before), for which all future SELs point to.

This is done for less memory usage, and easier message forwarding.

Richard J. Ross III
  • 55,009
  • 24
  • 135
  • 201
  • There are many times when I wonder if you are secretly working on the ObjC runtime, and this is one of them... +1 – CodaFi Jun 15 '12 at 13:48
  • Thank you for help and lovely answer. – S.J Jun 15 '12 at 13:53
  • @RichardJ.Ross: `!No = YES`. ;) – CodaFi Jun 15 '12 at 13:54
  • 1
    While the details are correct, the conclusion misses the most important reasons why this is done. – bbum Jun 15 '12 at 14:18
  • @bbum I disagree `This is done for less memory usage, and easier message forwarding.` is that not clear enough? – Richard J. Ross III Jun 15 '12 at 14:24
  • 2
    Not a clarity issue, but accuracy. It is for speed, *speed*, **speed**. Check out the cache lookup implementation for `objc_msgSend()`; every single method call -- all 100s of millions of them when you boot a device -- relies on the uniqueness of selectors to allow the cache lookup and message dispatch to be as fast as possible (or as fast as the team knows how to make it, anyway :). – bbum Jun 15 '12 at 14:38
4

It also, though, refers to the unique identifier that replaces the name when the source code is compiled... All methods with the same name have the same selector.

For this, I refer to an excellent blog post on selectors:

A selector is the same for all methods that have the same name and parameters — regardless of which objects define them, whether those objects are related in the class hierarchy, or actually have nothing to do with each other. At runtime, Objective-C goes to the class and outright asks it, "Do you respond to this selector?", and calls the resulting function pointer if it does.

The runtime system makes sure each identifier is unique: No two selectors are the same, and all methods with the same name have the same selector.

In a screwed up way, this makes sense. If Method A and Method B have the exact same name and arguments, wouldn't it be more efficient to store their selector as one lookup and query the receiver instead of deciding between two basically equally named selectors at runtime?

CodaFi
  • 43,043
  • 8
  • 107
  • 153
2

Look at the SEL type, you don't have to define which class this selector is from, you just give it a method name, for example:

SEL animationSelector = @selector(addAnimation:forKey:); 

You can imagine it as a streetname, for example. Many cities can have the same streetnames, but a streetname without a city is worthless. Same for selectors, you can define a selector without adding the object where it's in. But it's complete worthless without fitting class..

Herm
  • 2,956
  • 19
  • 32
  • thank you for help and helping me understand this topic with this city street name example :) . – S.J Jun 15 '12 at 13:55