Swift isa-переназначение указателя или другой поддерживаемый метод swizzling
У классов Swift есть что-то вроде указателя isa, который можно переназначить?
Мы видели, что Swift использует более статический метод отправки, чем objective-C, который (если только класс dervices из Foundation/NSObject) не предотвращает стиль swizzling основанный на реализации методов переопределения во время выполнения.
Мне интересно, как мы будем использовать динамические функции на основе перехвата меток, такие как шаблон наблюдателя, уведомления и т.д.? В настоящее время все эти материалы предоставляются слоем Objective-C и могут быть легко интегрированы в Swift. Но, если мы хотим предоставить эти функции в рамках (или приложениях) наших собственных, необходимо ли их реализовать в Objective-C? Я бы предположил, что есть способ сделать это "изначально".
Другой вид swizzling, общий для Objective-C, переназначает isa-указатель для генерации подкласса "на лету". Этот вид swizzling поддерживается в Swift? Если не существует поддерживаемый способ перехвата произвольных вызовов метода?
Изменить: Как указывает @jatoben, с arm64 isa-переназначение должно выполняться вызовом object_setClass(), а не путем прямого доступа к значению. Это по-прежнему называется "isa pointer swizzling"
Ответы
Ответ 1
Похоже, что и обмен методой, и метод переопределения указателя isa работают только в том случае, если класс Swift имеет NSObject в качестве суперкласса (прямо или вверх). В настоящее время он не работает, когда класс Swift не имеет суперкласса или какого-либо другого базового класса, отличного от Foundation.
Следующий тест показывает это:
Класс: Птичка
class Birdy: NSObject {
func sayHello()
{
println("tweet tweet")
}
}
Класс: HodorBirdy
class HodorBirdy: Birdy {
override func sayHello()
{
super.sayHello()
println("hodor hodor")
}
}
Тест:
func testExample() {
var birdy : Birdy = Birdy()
object_setClass(birdy, HodorBirdy.self)
birdy.sayHello();
}
И результат был таким, как ожидалось:
tweet tweet
hodor hodor
В этом тесте оба базового класса и подкласса были созданы заранее. Хотя они также могут быть созданы динамически с использованием среды выполнения Objective-C, пока класс NSObject является предком.
Если класс Swift не основан на фундаменте Objective-C, тогда компилятор будет поддерживать отправку на основе статики или vtable, поэтому неясно, как в этом случае будет работать перехват методов!
Если язык/компилятор не дает конкретного разрешения на это, мы будем выступать за динамизм в пользу производительности. (Перехват, который является основой "динамического" поведения, может быть выполнен либо во время компиляции, либо во время выполнения. В случае статической или виртуальной отправки без виртуальной машины применяется только время компиляции.
Ответ 2
Я не могу ответить на ваш вопрос о быстром эквиваленте "isa", но я думаю, что знаю часть ответа на ваш основной вопрос.
Собственные наблюдатели кажутся встроенными средствами для шаблона наблюдателя. Вместо обнаружения времени "тип" (RTTI, what-have-you) оно соткано в явном виде.
Из языка "Быстрый язык программирования" стр. 345:
Наблюдатели свойств наблюдают и реагируют на изменения в свойствах стоимость. Наблюдатели свойств вызывается каждый раз, когда значение свойства set, даже если новое значение совпадает с текущим значением свойства значение.
Вы можете добавить наблюдателей свойств к любым сохраненным свойствам, которые вы определяете, кроме ленивых хранимых свойств. Вы также можете добавить наблюдателей свойств к любому унаследованному свойству (независимо от того, хранятся или вычисляются) путем переопределения свойство в подклассе.
У вас есть возможность определить одного или обоих этих наблюдателей на Свойство:
- willSet вызывается непосредственно перед сохранением значения.
- didSet вызывается сразу после сохранения нового значения.
Я не уверен, как все это сработает, но я заинтригован.
Полагая, что обнаружение типа времени выполнения также, похоже, противоречит сильной ортодоксии статического типа.