应用示例,利用Runtime给所有UIViewController添加全屏返回功能

一.入口,重写UIApplicationnext方法

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关键字的特性–防止被重写.