-
Notifications
You must be signed in to change notification settings - Fork 43
/
Copy pathSwizzle.swift
50 lines (38 loc) · 1.42 KB
/
Swizzle.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import ObjectiveC
nonisolated(unsafe) public var swizzleLogs = false
@MainActor
public func swizzle(_ type: AnyObject.Type, _ original: Selector, _ swizzled: Selector) {
guard !swizzlingHistory.contains(type, original, swizzled) else {
return
}
swizzlingHistory.add(type, original, swizzled)
guard let originalMethod = class_getInstanceMethod(type, original) else {
assertionFailure("[Swizzling] Instance method \(type).\(original) not found.")
return
}
guard let swizzledMethod = class_getInstanceMethod(type, swizzled) else {
assertionFailure("[Swizzling] Instance method \(type).\(swizzled) not found.")
return
}
if swizzleLogs {
print("[Swizzling] [\(type) \(original) <~> \(swizzled)]")
}
method_exchangeImplementations(originalMethod, swizzledMethod)
}
private struct SwizzlingHistory {
private var map: [Int: Void] = [:]
func contains(_ type: AnyObject.Type, _ original: Selector, _ swizzled: Selector) -> Bool {
map[hash(type, original, swizzled)] != nil
}
mutating func add(_ type: AnyObject.Type, _ original: Selector, _ swizzled: Selector) {
map[hash(type, original, swizzled)] = ()
}
private func hash(_ type: AnyObject.Type, _ original: Selector, _ swizzled: Selector) -> Int {
var hasher = Hasher()
hasher.combine(ObjectIdentifier(type))
hasher.combine(original)
hasher.combine(swizzled)
return hasher.finalize()
}
}
nonisolated(unsafe) private var swizzlingHistory = SwizzlingHistory()