Understanding uniqueness of selectors in Objective-C

前端 未结 4 1602
死守一世寂寞
死守一世寂寞 2021-01-15 03:50

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:

相关标签:
4条回答
  • 2021-01-15 04:10

    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..

    0 讨论(0)
  • 2021-01-15 04:15

    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.

    0 讨论(0)
  • 2021-01-15 04:20

    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?

    0 讨论(0)
  • 2021-01-15 04:23

    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.

    0 讨论(0)
提交回复
热议问题