Skip to content

Instantly share code, notes, and snippets.

@codelynx
Created March 17, 2021 09:10
Show Gist options
  • Save codelynx/3685e0530607746a0811dfd3d1feff9e to your computer and use it in GitHub Desktop.
Save codelynx/3685e0530607746a0811dfd3d1feff9e to your computer and use it in GitHub Desktop.
Example of swizzling UIKit classes
//
// UIKit+swizzling.swift
//
// The MIT License (MIT)
//
// Copyright (c) 2022 Electricwoods LLC, Kaz Yoshikawa.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import Foundation
import UIKit
import PlaygroundSupport
fileprivate func swizzleMethod(_ `class`: AnyClass, _ original: Selector, _ swizzled: Selector) {
if let original = class_getInstanceMethod(`class`, original), let swizzled = class_getInstanceMethod(`class`, swizzled) {
method_exchangeImplementations(original, swizzled)
}
else { print("failed to swizzle: \(`class`.self), '\(original)', '\(swizzled)'") }
}
public extension UIViewController {
fileprivate static func swizzele_UIViewController() {
swizzleMethod(UIViewController.self, #selector(UIViewController.viewDidLoad), #selector(UIViewController.viewDidLoad_x))
swizzleMethod(UIViewController.self, #selector(UIViewController.viewWillAppear(_:)), #selector(UIViewController.viewWillAppear_x(_:)))
swizzleMethod(UIViewController.self, #selector(UIViewController.viewDidAppear(_:)), #selector(UIViewController.viewDidAppear_x(_:)))
swizzleMethod(UIViewController.self, #selector(UIViewController.viewWillDisappear(_:)), #selector(UIViewController.viewWillDisappear_x(_:)))
swizzleMethod(UIViewController.self, #selector(UIViewController.viewDidDisappear(_:)), #selector(UIViewController.viewDidDisappear_x(_:)))
swizzleMethod(UIViewController.self, #selector(UIViewController.viewWillLayoutSubviews), #selector(UIViewController.viewWillLayoutSubviews_x))
swizzleMethod(UIViewController.self, #selector(UIViewController.viewDidLayoutSubviews), #selector(UIViewController.viewDidLayoutSubviews_x))
}
@objc private func viewDidLoad_x() {
print(Self.self, #function)
self.viewDidLoad_x()
}
@objc private func viewWillAppear_x(_ animated: Bool) {
print(Self.self, #function)
self.viewWillAppear_x(animated)
}
@objc private func viewDidAppear_x(_ animated: Bool) {
print(Self.self, #function)
self.viewDidAppear_x(animated)
}
@objc private func viewWillDisappear_x(_ animated: Bool) {
print(Self.self, #function)
self.viewWillDisappear_x(animated)
}
@objc private func viewDidDisappear_x(_ animated: Bool) {
print(Self.self, #function)
self.viewDidDisappear_x(animated)
}
@objc private func viewWillLayoutSubviews_x() {
print(Self.self, #function)
self.viewWillLayoutSubviews_x()
}
@objc private func viewDidLayoutSubviews_x() {
print(Self.self, #function)
self.viewDidLayoutSubviews_x()
}
}
public extension UIView {
fileprivate static func swizzele_UIView() {
swizzleMethod(UIView.self, #selector(UIView.layoutSubviews), #selector(UIView.layoutSubviews_x))
swizzleMethod(UIView.self, #selector(UIView.draw(_:)), #selector(UIView.draw_x(_:)))
swizzleMethod(UIView.self, #selector(UIView.sizeThatFits(_:)), #selector(UIView.sizeThatFits_x(_:)))
}
@objc private func layoutSubviews_x() {
print(Self.self, #function)
self.layoutSubviews_x()
}
@objc private func draw_x(_ rect: CGRect) {
print(Self.self, #function)
self.draw_x(rect)
}
@objc private func sizeThatFits_x(_ size: CGSize) -> CGSize {
print(Self.self, #function)
return self.sizeThatFits_x(size)
}
}
public extension UIControl {
fileprivate static func swizzele_UIControl() {
swizzleMethod(UIControl.self, #selector(UIControl.sendAction(_:to:for:)), #selector(UIControl.sendAction_x(_:to:for:)))
swizzleMethod(UIControl.self, #selector(UIControl.sendActions(for:)), #selector(UIControl.sendAction_x(for:)))
}
@objc private func sendAction_x(_ action: Selector, to target: Any?, for event: UIEvent?) {
print(Self.self, #function)
self.sendAction_x(action, to: target, for: event)
}
@objc private func sendAction_x(for controlEvents: UIControl.Event) {
print(Self.self, #function)
self.sendAction_x(for: controlEvents)
}
}
UIViewController.swizzele_UIViewController()
UIView.swizzele_UIView()
UIControl.swizzele_UIControl()
class MyViewController : UIViewController {
lazy var button: UIButton = {
let button = UIButton(frame: CGRect.zero)
button.setTitle("Hello", for: .normal)
button.setTitleColor(UIColor.blue, for: .normal)
button.layer.borderColor = UIColor.blue.cgColor
button.layer.borderWidth = 1
button.layer.cornerRadius = 5
button.addTarget(self, action: #selector(Self.buttonAction(_:)), for: .touchUpInside)
return button
}()
override func loadView() {
let view = UIView()
self.view = view
view.backgroundColor = .white
view.addSubview(self.button)
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
self.button.bounds.size = CGSize(width: 100, height: 40)
self.button.center = self.view.center
}
@objc func buttonAction(_ sender: UIButton) {
print(Self.self, #function)
}
}
PlaygroundPage.current.liveView = MyViewController()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment