Ответ
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только в своих классах).