2012-06-15 1 views
2

У меня проблема с пониманием части функции «селекторов», как описано в руководстве Apple. Я выделил части, где меня путают:Понимание уникальности селекторов в Objective-C

В Objective-C селектор имеет два значения. Его можно использовать для ссылки просто на имя метода, когда он используется в сообщении исходного кода объекту. Он также ссылается на уникальный идентификатор, который заменяет имя при компиляции исходного кода. Составленные селектора типа SEL. У всех методов с тем же именем есть такой же селектор . Вы можете использовать селектор для вызова метода на объекте - это обеспечивает основу для реализации шаблона целевого действия в Cocoa.

Методы и селекторы Для эффективности полные имена ASCII не используются как селектора методов в скомпилированном коде. Вместо этого компилятор записывает каждое имя метода в таблицу, затем сопоставляет имя с уникальным идентификатором , который представляет метод во время выполнения. Система времени выполнения гарантирует, что каждый идентификатор уникален: ни один из двух селекторов не будет таким же, и все методы с тем же именем имеют один и тот же селектор.

Может ли кто-нибудь объяснить эти биты? Кроме того, если у разных классов есть методы с тем же именем, будет ли они также иметь один и тот же селектор?

ответ

12

Все селекторы уникальны - как во время компиляции, так и, динамически, во время выполнения через sel_getUid() или предпочтительный (последний в основном предпочтен, первый по-прежнему существует по историческим причинам) - для скорость.

Предыстория: для вызова метода для выполнения требуется селектор, который идентифицирует то, что должно быть вызвано, и объект, на который он будет вызываться. Вот почему каждый вызов метода в Objective-C имеет два параметра: очевидный и известный self и невидимый, подразумеваемый параметр _cmd. _cmd - это SEL текущего метода. То есть, вы можете вставить этот код в любой метод, чтобы увидеть название - селектор - метода исполняемой в данный момент:

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

Обратите внимание, что _cmd является не глобальным; это действительно аргумент для вашего метода. Смотри ниже.

Унифицируя селектор, все операции на основе селектора реализуются с использованием тестов равенства указателя вместо обработки строк или вообще любого указателя.

В частности, каждый раз, когда вы делаете вызов метода:

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

компилятор генерирует этот код (или очень тесно связаны вариант):

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

Самое первое, что objc_msgSend() делает это проверка, чтобы узнать, является ли someObject нулевым и короткое замыкание, если оно (сообщение nil-eat-message). Следующий (игнорирующий тегированные указатели) должен искать селектор в классе someObject (указатель isa, по сути), найти реализацию и называть его (с помощью оптимизации хвостового вызова).

Это найти реализацию вещь должна быть быстрой и сделать ее очень быстрой, вы хотите, чтобы ключ к нахождению реализации метода был максимально быстрым и стабильным. Чтобы сделать , что, вы хотите, чтобы ключ был непосредственно полезным и глобально уникальным для процесса.

Таким образом, селектора являются уникальными.

То, что это также спасает память, является фантастическим преимуществом, но посланник будет использовать больше памяти, чем сегодня, если бы messenging можно было сделать 2x быстрее (но не 10x для 2x - или даже 2x памяти для 2x скорости - - в то время как скорость критическая, использование памяти также критично, конечно).

Если вы действительно хотите глубоко погрузиться в то, как работает objc_msgSend(), я написал bit of a guide. Обратите внимание, что он немного устарел, поскольку он был написан до указателей с метками, блоков-в-реализации и ARC. Я должен обновить статьи.

+0

WOW какой фантастический повтор, спасибо большое. Пожалуйста, дайте мне несколько советов, как я могу улучшить свои навыки, как вы. –

+0

Добро пожаловать; как улучшить? Практика. Я занимаюсь этим довольно долго. :) – bbum

+0

:) ... я очень стараюсь, но все еще не хватает ... –

4

Он также относится к уникальному идентификатору, который заменяет имя при компиляции исходного кода ... Все методы с тем же именем имеют один и тот же селектор.

Для этого я отсылаю к превосходному blog post на селекторы:

Селектор одинакова для всех методов, которые имеют такое же имя и параметры - независимо от того, какие объекты определяют их, будь те объекты, связаны в иерархии классов или фактически не имеют ничего общего друг с другом. Во время выполнения Objective-C переходит в класс и прямо спрашивает его: «Вы отвечаете на этот селектор?» И называет полученный результирующий указатель функции, если он это делает.

Система времени выполнения гарантирует, что каждый идентификатор уникален: ни один из двух селекторов не является одним и тем же, и все методы с тем же именем имеют один и тот же селектор.

В отвратительном способе это имеет смысл. Если метод A и метод B имеют одинаковые имена и аргументы, не было бы более эффективным хранить их селектор в качестве одного поиска и запрашивать приемник вместо того, чтобы выбирать между двумя в основном одинаково названными селекторами во время выполнения?

+0

благодарит вас за помощь и помощь в понимании этой темы. –

+0

Конечно. Счастливое кодирование, мадам. – CodaFi

5

Да. Классы разделяют селекторы.

Я могу привести пример из исходного кода objc-sel.mm, но при использовании sel_registerUid() (используется за кулисами в @selector()), копирует входной строки во внутренний буфер (если строка не была зарегистрирована ранее) , на которые указывают все будущие SELs.

Это делается для меньшего использования памяти и упрощения пересылки сообщений.

+0

Есть много раз, когда я задаюсь вопросом, тайно ли вы работаете над временем выполнения ObjC, и это один из них ... +1 – CodaFi

+0

@CodaFi, который говорит, что я этого не делаю? –

+0

Благодарим вас за помощь и прекрасный ответ. –

2

Посмотрите на тип SEL, вы не должны определить, какой класс этот селектор из, вы просто дать ему имя метода, например:

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

Вы можете представить его как StreetName, например. Многие города могут иметь одни и те же уличные имена, но имя улицы без города бесполезно. То же самое для селекторов, вы можете определить селектор, не добавляя объект, где он находится. Но он совершенно бесполезен без соответствующего класса.

+0

благодарим вас за помощь и помощь в понимании этой темы с этим примером названия улицы города :). –