应用示例,利用Runtime给所有UIViewController添加全屏返回功能
一.入口,重写UIApplication
的next
方法
extension UIApplication {
private static let runOnce: Void = {
NothingToSeeHere.harmlessFunction()
}()
// 在applicationDidFinishLaunching方法之前调用
override open var next: UIResponder? {
UIApplication.runOnce
return super.next
}
}
定义一个类,定义一个静态方法,在这个方法中拿到所有遵守协议的类,进行方法的交换
class NothingToSeeHere {
static func harmlessFunction() {
// 打印 11930 获取所有的类数量
let typeCount = Int(objc_getClassList(nil, 0))
// 在Swift中无类型的指针,原始内存可以用UnsafeRawPointer 和UnsafeMutableRawPointer来表示
// 定义一个存放类的数组,capacity指定分配内存大小
// 不提供自动内存管理,没有类型安全性
let types = UnsafeMutablePointer<AnyClass>.allocate(capacity: typeCount)
let autoreleasingTypes = AutoreleasingUnsafeMutablePointer<AnyClass>(types)
// 获取所有的类,存放到数组types
objc_getClassList(autoreleasingTypes, Int32(typeCount))
// 如果该类实现了SelfAware协议,那么调用awake方法
for index in 0 ..< typeCount {
(types[index] as? SelfAware.Type)?.awake()
}
// types.deallocate(capacity: typeCount)
// 释放
types.deallocate()
}
}
// MARK:- SelfAware 定义协议,使得程序在初始化的时候,将遵循该协议的类做了方法交换
protocol SelfAware: class {
static func awake()
}
遵守协议,实现协议方法
// MARK:UIViewController 交换viewWillAppear(_:)与viewWillDisappear(_:)方法
extension UIViewController:SelfAware {
static func awake() {
UIViewController.classInit()
UINavigationController.classInitial()
}
static func classInit() {
swizzleMethod
}
private static let swizzleMethod: Void = {
let originalSelector = #selector(viewWillAppear(_:))
let swizzledSelector = #selector(swizzled_viewWillAppear(_:))
swizzlingForClass(UIViewController.self, originalSelector: originalSelector, swizzledSelector: swizzledSelector)
let originalSelector1 = #selector(viewWillDisappear(_:))
let swizzledSelector1 = #selector(swizzled_viewWillDisAppear(_:))
swizzlingForClass(UIViewController.self, originalSelector: originalSelector1, swizzledSelector: swizzledSelector1)
}()
…
}
导航控制器
// MARK:UINavigationController 交换pushViewController(_:animated:)方法
extension UINavigationController {
static func classInitial() {
swizzleMethod
}
private static let swizzleMethod: Void = {
let originalSelector = #selector(UINavigationController.pushViewController(_:animated:))
let swizzledSelector = #selector(dx_pushViewController)
swizzlingForClass(UINavigationController.self, originalSelector: originalSelector, swizzledSelector: swizzledSelector)
}()
…
}
二.如何在Swift中给分类添加关联属性
extension UIViewController {
// MARK:- RuntimeKey 动态绑属性
struct RuntimeKey {
// 在Swift中无类型的指针,原始内存可以用UnsafeRawPointer 和UnsafeMutableRawPointer来表示
// A raw pointer for accessing untyped data 用于访问非类型数据的原始指针
// init(bitPattern:) 从指定地址创建一个新的原始指针,指定为位模式
// 哈希: http://swifter.tips/hash/
// 比如 Int 的 hashValue 就是它本身:
// print("dx_popDisabled".hashValue) 402467026446327185
static let dx_popDisabled = UnsafeRawPointer.init(bitPattern: "dx_popDisabled".hashValue)
static let dx_navigationBarHidden = UnsafeRawPointer.init(bitPattern: "dx_navigationBarHidden".hashValue)
}
// MARK:- 是否开启侧滑,默认true
public var dx_popDisabled: Bool? {
set {
objc_setAssociatedObject(self, RuntimeKey.dx_popDisabled!, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get {
return objc_getAssociatedObject(self, RuntimeKey.dx_popDisabled!) as? Bool
}
}
关键字static和class的区别
在方法的func关键字之前加上关键字static或者class都可以用于指定类方法. 不同的是用class关键字指定的类方法可以被子类重写, 如下:
override class func work() {
print("Teacher: University Teacher")
}
但是用static关键字指定的类方法是不能被子类重写的, 根据报错信息: Class method overrides a ‘final’ class method. 我们可以知道被static指定的类方法包含final关键字的特性–防止被重写.