前言
Runtime介绍
学习一个东西至少要先知道它是个啥,你一定听说过“运行时是 Objective-C 的一个特色”,这里的“运行时”就是指 runtime 了。
老的方式initialize现在已经不适用了,需要用新的方式代替。
思路: 定义一个启动的协议,在app完成启动的方法里把需要做method swizzle的类跑一边协议的方法
第一种
1、Step One
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
protocol SelfAware: class { static func awake() } class NothingToSeeHere { static func harmlessFunction() { let typeCount = Int(objc_getClassList(nil, 0)) let types = UnsafeMutablePointer<AnyClass?>.allocate(capacity: typeCount) let autoreleasingTypes = AutoreleasingUnsafeMutablePointer<AnyClass?>(types) objc_getClassList(autoreleasingTypes, Int32(typeCount)) for index in 0 ..< typeCount { (types[index] as? SelfAware.Type)?.awake() } types.deallocate(capacity: typeCount) } } |
2、step two
1
2
3
4
5
6
7
8
9
10
11
|
extension UIApplication { private static let runOnce: Void = { NothingToSeeHere.harmlessFunction() }() override open var next: UIResponder? { // Called before applicationDidFinishLaunching UIApplication.runOnce return super.next } } |
3、step three
遵循协议SelfAware,实现awake()
第二种(类似第一种)
1、创建一个swizzle注入的协议
1
2
3
|
public protocol SwizzlingInjection: class { static func inject() } |
2、创建swizzle helper
1
2
3
4
5
6
7
8
9
10
11
|
open class SwizzlingManager { //只会调用一次的方法 private static let doOnce: Any? = { UIViewController.inject() return nil }() open static func enableInjection() { _ = SwizzlingManager.doOnce } } |
3、给UIApplication 创建分类调用那个一次方法
1
2
3
4
5
6
|
extension UIApplication{ open override var next: UIResponder?{ SwizzlingManager.enableInjection() return super.next } } |
4、在你需要的类中遵循注入协议
1
2
3
4
5
6
7
8
9
10
|
extension UIViewController: SwizzlingInjection{ public static func inject() { //确保不是子类 guard self === UIViewController.self else { return } DispatchQueue.once(token: "com.moglo.urmoji.UIViewController" ) { //do swizzle method } } } |
once只执行一次的方法
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
51
52
53
54
55
56
57
58
|
public extension DispatchQueue { private static var _onceTracker = [String]() public class func once(file: String = #file, function: String = #function, line: Int = #line, block:()->Void) { let token = file + ":" + function + ":" + String(line) once(token: token, block: block) } /** Executes a block of code, associated with a unique token, only once. The code is thread safe and will only execute the code once even in the presence of multithreaded calls. - parameter token: A unique reverse DNS style name such as com.vectorform.<name> or a GUID - parameter block: Block to execute once */ public class func once(token: String, block:()->Void) { objc_sync_enter(self) defer { objc_sync_exit(self) } if _onceTracker.contains(token) { return } _onceTracker.append(token) block() } //delay typealias Task = (_ cancel : Bool) -> Void @discardableResult static func delay( time : TimeInterval, task: @escaping () -> ()) -> Task? { func dispatch_later(block : @escaping () -> ()) { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + time , execute: block) } var closure : (() -> ())? = task var result : Task? let delayedClosure : Task = { cancel in if let internalClosure = closure { if cancel == false { DispatchQueue.main.async(execute: internalClosure) } } closure = nil result = nil } result = delayedClosure dispatch_later { () -> () in if let delayedClosure = result { delayedClosure( false ) } } return result } static func cancel(task : Task?) { task?( true ) } } |
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。
原文链接:https://www.jianshu.com/p/335ba236b56a