Ответ
Method swizzling — это техника подмены реализации метода во время выполнения (runtime) путем обмена указателей на реализации (implementations) двух методов. Используется в крайних случаях для отладки, логирования или добавления функциональности, когда другие подходы (наследование, делегирование, композиция) неприменимы.
Пример: добавление логирования ко всем вызовам viewDidLoad в UIViewController.
import UIKit
extension UIViewController {
// 1. Объявляем новый метод для подмены
@objc dynamic func swizzled_viewDidLoad() {
// 2. Вызываем оригинальную реализацию (теперь она доступна под именем `swizzled_viewDidLoad`)
swizzled_viewDidLoad()
// 3. Добавляем свою логику
print("[Swizzle] ViewDidLoad called for: (type(of: self))")
}
// 4. Статический метод для однократного выполнения swizzling
static func swizzleViewDidLoad() {
// Гарантируем выполнение только один раз
guard self === UIViewController.self else { return }
let originalSelector = #selector(viewDidLoad)
let swizzledSelector = #selector(swizzled_viewDidLoad)
guard
let originalMethod = class_getInstanceMethod(self, originalSelector),
let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)
else {
print("Swizzling failed: methods not found")
return
}
// 5. Меняем реализации местами
method_exchangeImplementations(originalMethod, swizzledMethod)
}
}
// Вызов в AppDelegate при запуске приложения:
// UIViewController.swizzleViewDidLoad()
Ключевые моменты и best practices:
@objc dynamic: Обязателен для методов, участвующих в swizzling, чтобы включить динамическую диспетчеризацию Objective-C runtime.- Вызов оригинала: Всегда вызывайте оригинальную реализацию (под новым именем), чтобы не сломать ожидаемое поведение системы или фреймворка.
- Однократность: Swizzling должен выполняться только один раз, обычно в
+load(Objective-C) или в инициализаторе AppDelegate (Swift). В примере используется проверкаself === UIViewController.self. - Опасности: Может привести к сложно отлаживаемым ошибкам, конфликтам между библиотеками и поломке при обновлениях iOS. Избегайте в продакшн-коде, если есть альтернативы.
- Альтернативы: Рассмотрите использование делегирования, подклассов, композиции или сабклассинга (например, через
method_exchangeImplementationsтолько в своих классах).
Ответ 18+ 🔞
А, ну вот, блядь, метод свёзлинг! Это когда ты такой: «А давайте-ка я, сука, подменю реализацию метода прямо в рантайме, на ходу, как в кино про хакеров». Ну, типа, меняешь указатели на функции местами, и все дела. Используется, когда уже совсем припёрло — для отладки, логирования или воткнуть какую-нибудь фичу, когда нормальные пути (наследование, делегирование) уже в пизду улетели.
Вот, смотри, пример: как прикрутить логирование ко всем вызовам viewDidLoad в UIViewController.
import UIKit
extension UIViewController {
// 1. Объявляем наш подменный метод
@objc dynamic func swizzled_viewDidLoad() {
// 2. Вызываем оригинал (он теперь под этим именем прячется, ёпта)
swizzled_viewDidLoad()
// 3. А тут наша дичь — логируем
print("[Swizzle] ViewDidLoad called for: (type(of: self))")
}
// 4. Статический метод, чтобы этот цирк запустить один раз
static func swizzleViewDidLoad() {
// Сделаем вид, что мы умные, и не наебём систему дважды
guard self === UIViewController.self else { return }
let originalSelector = #selector(viewDidLoad)
let swizzledSelector = #selector(swizzled_viewDidLoad)
guard
let originalMethod = class_getInstanceMethod(self, originalSelector),
let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)
else {
print("Swizzling failed: methods not found")
return
}
// 5. Ну и, собственно, сам развод — меняем их местами, как в напёрстках
method_exchangeImplementations(originalMethod, swizzledMethod)
}
}
// Запускаем этот аттракцион в AppDelegate при старте:
// UIViewController.swizzleViewDidLoad()
А теперь, блядь, ключевые моменты, чтобы не обосраться:
@objc dynamic: Это, сука, обязательно. Без этого Objective-C runtime тебя не увидит, и вся магия накроется медным тазом.- Вызов оригинала: Ты ж не мудак? Всегда вызывай оригинальную реализацию (которая теперь под новым именем), а то сломаешь всё, что только можно. Овердохуища проблем потом будет.
- Один раз, и хватит: Запускать этот трюк нужно один-единственный раз, обычно при старте приложения. У меня в примере проверка
self === UIViewController.selfкак раз от дурака страхует. - Опасности, ёпта: Это пиздец как мощно, но и ломает всё с невероятной силой. Могут быть конфликты с другими библиотеками, всё полетит к чертям после обновления iOS. В продакшне лучше не выёбывайся, если есть нормальный путь.
- Альтернативы: О, их дохуя! Делегирование, подклассы, композиция... Ну или хотя бы свёзлинг делай только в своих классах, а не лезь в системные, как последний распиздяй.