ios 如何实现方法 swizzling swift 3.0?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/39562887/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to implement method swizzling swift 3.0?
提问by Tikhonov Alexander
How can I implement method swizzling in Swift 3.0?
如何在Swift 3.0 中实现方法 swizzling ?
I've read nshipster articleabout it, but in this code's chunk
我已经阅读了关于它的nshipster 文章,但在这段代码的块中
struct Static {
static var token: dispatch_once_t = 0
}
the compiler gives me an error
编译器给了我一个错误
dispatch_once_t is unavailable in Swift: Use lazily initialized globals instead
dispatch_once_t 在 Swift 中不可用:改用延迟初始化的全局变量
回答by Tikhonov Alexander
First of all dispatch_once_t
is unavailable in Swift 3.0.
You can choose from two alternatives:
首先dispatch_once_t
在 Swift 3.0 中不可用。您可以从两个选项中进行选择:
Global variable
Static property of
struct
,enum
orclass
全局变量
的静态属性
struct
,enum
或class
For more details, see that Whither dispatch_once in Swift 3
有关更多详细信息,请参阅Swift 3 中的 Whither dispatch_once
For different purposes you must use different implementation of swizzling
对于不同的目的,您必须使用不同的 swizzling 实现
- Swizzling CocoaTouch class, for example UIViewController;
- Swizzling custom Swift class;
- Swizzling CocoaTouch 类,例如 UIViewController;
- Swizzling 自定义 Swift 类;
Swizzling CocoaTouch class
Swizzling CocoaTouch 类
example swizzling viewWillAppear(_:)
of UIViewController
using global variable
例如混写viewWillAppear(_:)
的UIViewController
使用全局变量
private let swizzling: (UIViewController.Type) -> () = { viewController in
let originalSelector = #selector(viewController.viewWillAppear(_:))
let swizzledSelector = #selector(viewController.proj_viewWillAppear(animated:))
let originalMethod = class_getInstanceMethod(viewController, originalSelector)
let swizzledMethod = class_getInstanceMethod(viewController, swizzledSelector)
method_exchangeImplementations(originalMethod, swizzledMethod) }
extension UIViewController {
open override class func initialize() {
// make sure this isn't a subclass
guard self === UIViewController.self else { return }
swizzling(self)
}
// MARK: - Method Swizzling
func proj_viewWillAppear(animated: Bool) {
self.proj_viewWillAppear(animated: animated)
let viewControllerName = NSStringFromClass(type(of: self))
print("viewWillAppear: \(viewControllerName)")
}
}
Swizzling custom Swift class
Swizzling 自定义 Swift 类
To use method swizzling with your Swift classes there are two requirements that you must comply with (for more details):
要在 Swift 类中使用方法 swizzling,您必须遵守两个要求(有关更多详细信息):
- The class containing the methods to be swizzled must extend
NSObject
- The methods you want to swizzle must have the
dynamic
attribute
- 包含要调配的方法的类必须扩展
NSObject
- 您要 swizzle 的方法必须具有该
dynamic
属性
And example swizzling method of custom Swift base class Person
以及自定义 Swift 基类的示例 swizzling 方法 Person
class Person: NSObject {
var name = "Person"
dynamic func foo(_ bar: Bool) {
print("Person.foo")
}
}
class Programmer: Person {
override func foo(_ bar: Bool) {
super.foo(bar)
print("Programmer.foo")
}
}
private let swizzling: (Person.Type) -> () = { person in
let originalSelector = #selector(person.foo(_:))
let swizzledSelector = #selector(person.proj_foo(_:))
let originalMethod = class_getInstanceMethod(person, originalSelector)
let swizzledMethod = class_getInstanceMethod(person, swizzledSelector)
method_exchangeImplementations(originalMethod, swizzledMethod)
}
extension Person {
open override class func initialize() {
// make sure this isn't a subclass
guard self === Person.self else { return }
swizzling(self)
}
// MARK: - Method Swizzling
func proj_foo(_ bar: Bool) {
self.proj_foo(bar)
let className = NSStringFromClass(type(of: self))
print("class: \(className)")
}
}
回答by efremidze
@TikhonovAlexander: Great answer
@TikhonovAlexander:很好的答案
I modified the swizzler to take both selectors and made it more generic.
我修改了 swizzler 以采用两个选择器并使其更通用。
Swift 3
斯威夫特 3
private let swizzling: (AnyClass, Selector, Selector) -> () = { forClass, originalSelector, swizzledSelector in
let originalMethod = class_getInstanceMethod(forClass, originalSelector)
let swizzledMethod = class_getInstanceMethod(forClass, swizzledSelector)
method_exchangeImplementations(originalMethod, swizzledMethod)
}
// perform swizzling in initialize()
extension UIView {
open override class func initialize() {
// make sure this isn't a subclass
guard self === UIView.self else { return }
let originalSelector = #selector(layoutSubviews)
let swizzledSelector = #selector(swizzled_layoutSubviews)
swizzling(self, originalSelector, swizzledSelector)
}
func swizzled_layoutSubviews() {
swizzled_layoutSubviews()
print("swizzled_layoutSubviews")
}
}
Swift 4
斯威夫特 4
private let swizzling: (AnyClass, Selector, Selector) -> () = { forClass, originalSelector, swizzledSelector in
guard
let originalMethod = class_getInstanceMethod(forClass, originalSelector),
let swizzledMethod = class_getInstanceMethod(forClass, swizzledSelector)
else { return }
method_exchangeImplementations(originalMethod, swizzledMethod)
}
extension UIView {
static let classInit: Void = {
let originalSelector = #selector(layoutSubviews)
let swizzledSelector = #selector(swizzled_layoutSubviews)
swizzling(UIView.self, originalSelector, swizzledSelector)
}()
@objc func swizzled_layoutSubviews() {
swizzled_layoutSubviews()
print("swizzled_layoutSubviews")
}
}
// perform swizzling in AppDelegate.init()
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
override init() {
super.init()
UIView.classInit
}
}
回答by Dharay Mistry
swizzling in playground
Swift 4.2
在Swift 4.2 的操场上大摇大摆
import Foundation
class TestSwizzling : NSObject {
@objc dynamic func methodOne()->Int{
return 1
}
}
extension TestSwizzling {
//In Objective-C you'd perform the swizzling in load(),
//but this method is not permitted in Swift
func swizzle(){
let i: () -> () = {
let originalSelector = #selector(TestSwizzling.methodOne)
let swizzledSelector = #selector(TestSwizzling.methodTwo)
let originalMethod = class_getInstanceMethod(TestSwizzling.self, originalSelector);
let swizzledMethod = class_getInstanceMethod(TestSwizzling.self, swizzledSelector)
method_exchangeImplementations(originalMethod!, swizzledMethod!)
print("swizzled")
}
i()
}
@objc func methodTwo()->Int{
// It will not be a recursive call anymore after the swizzling
return 4
}
}
var c = TestSwizzling()
print([c.methodOne(),c.methodTwo()])
c.swizzle()
print([c.methodOne(),c.methodTwo()])
output:
[1, 4]
swizzled
[4, 1]
输出:
[1, 4]
混合
[4, 1]
回答by Yanni
Try this framework: https://github.com/623637646/SwiftHook
试试这个框架:https: //github.com/623637646/SwiftHook
let object = MyObject()
let token = try? hookBefore(object: object, selector: #selector(MyObject.noArgsNoReturnFunc)) {
// run your code
print("hooked!")
}
object.noArgsNoReturnFunc()
token?.cancelHook() // cancel the hook
It's very easy to hook methods in Swift.
在 Swift 中挂钩方法非常容易。
回答by mistdon
Swift 5.1
斯威夫特 5.1
Swift use Objective-C runtime feature to make method swizzling. Here you are two ways.
Swift 使用 Objective-C 运行时特性来进行方法 swizzling。这里有两种方法。
Note: open override class func initialize() {}
is not allowed anymore.
注意:open override class func initialize() {}
不再允许。
class inherit
NSObject
, and method must havedynamic
attributeclass Father: NSObject { @objc dynamic func makeMoney() { print("make money") } } extension Father { static func swizzle() { let originSelector = #selector(Father.makeMoney) let swizzleSelector = #selector(Father.swizzle_makeMoney) let originMethod = class_getInstanceMethod(Father.self, originSelector) let swizzleMethod = class_getInstanceMethod(Father.self, swizzleSelector) method_exchangeImplementations(originMethod!, swizzleMethod!) } @objc func swizzle_makeMoney() { print("have a rest and make money") } } Father.swizzle() var tmp = Father() tmp.makeMoney() // have a rest and make money tmp.swizzle_makeMoney() // make money
- Use
@_dynamicReplacement(for: )
class Father { dynamic func makeMoney() { print("make money") } } extension Father { @_dynamicReplacement(for: makeMoney()) func swizzle_makeMoney() { print("have a rest and make money") } } Father().makeMoney() // have a rest and make money
- Use
类继承
NSObject
,方法必须有dynamic
属性class Father: NSObject { @objc dynamic func makeMoney() { print("make money") } } extension Father { static func swizzle() { let originSelector = #selector(Father.makeMoney) let swizzleSelector = #selector(Father.swizzle_makeMoney) let originMethod = class_getInstanceMethod(Father.self, originSelector) let swizzleMethod = class_getInstanceMethod(Father.self, swizzleSelector) method_exchangeImplementations(originMethod!, swizzleMethod!) } @objc func swizzle_makeMoney() { print("have a rest and make money") } } Father.swizzle() var tmp = Father() tmp.makeMoney() // have a rest and make money tmp.swizzle_makeMoney() // make money
- 用
@_dynamicReplacement(for: )
class Father { dynamic func makeMoney() { print("make money") } } extension Father { @_dynamicReplacement(for: makeMoney()) func swizzle_makeMoney() { print("have a rest and make money") } } Father().makeMoney() // have a rest and make money
- 用