runtime 关联对象的简单运用

.关联对象

简单给UIButton添加一个分类,功能为按钮添加一个block处理按钮的点击事件。

objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key,
id _Nullable value, objc_AssociationPolicy policy)

第一个参数为对象 相当于 setValue:forKey 进行关联value对象
第二个为需要存储的对象的key值,
第三个为值,value
第四个 属性 是设定该value在object内的属性,即 assgin, (retain,nonatomic)...等

objc_setAssociatedObject(self, &KUibuttonBlockKey, block, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)

objc_getAssociatedObject 获取数据,相当于forkey来获取value

  let block:btnBlock? = objc_getAssociatedObject(self, &KUibuttonBlockKey) as? btnBlock
import UIKit
typealias btnBlock = ((Any?)->Void)
private var KUibuttonBlockKey = "KUibuttonBlockKey"
extension UIButton{
    func actionBlock(with block:btnBlock?) {
        if block != nil {
            objc_setAssociatedObject(self, &KUibuttonBlockKey, block, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        addTarget(self, action: #selector(butClick(_ :)), for: .touchUpInside)
    }
    @objc func butClick(_ sender:Any?){
        let block:btnBlock? = objc_getAssociatedObject(self, &KUibuttonBlockKey) as? btnBlock
        block?(sender)
    }
}
 override func viewDidLoad() {
        super.viewDidLoad()
        let bt = UIButton()
        bt.frame = CGRect(x: 100, y: 100, width: 100, height: 100)
        bt.backgroundColor = #colorLiteral(red: 0.5725490451, green: 0, blue: 0.2313725501, alpha: 1)
        bt.setTitle("ok", for: .normal)
        bt.setTitleColor(#colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0), for: .normal)
        view.addSubview(bt)
        bt.actionBlock { (bt) in
            print("bt \(bt as! UIButton)")
        }
    }

点击界面按钮,控制台打印:

bt >

.黑魔法

   let mettod = class_getInstanceMethod(UIViewController.classForCoder(), #selector(UIViewController.viewWillAppear(_:)))
   let mettod2 = class_getInstanceMethod(UIViewController.classForCoder(), #selector(UIViewController.swizzlingViewWillAppear(_:)))
        method_exchangeImplementations(mettod!, mettod2!)//替换这两个方法
import UIKit
var kHasBeenPoppedKey = "kHasBeenPoppedKey"

extension UIViewController{
    @objc func swizzlingViewWillAppear(_ animated : Bool){
        swizzlingViewWillAppear(animated)
        objc_setAssociatedObject(self, &kHasBeenPoppedKey, false, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
    @objc func swizzlingViewDidDisappear(_ animated:Bool){
        
        swizzlingViewDidDisappear(animated)
        let isOK:Bool = (objc_getAssociatedObject(self, &kHasBeenPoppedKey) as? Bool) ?? false
        if isOK {
            DispatchQueue.global().asyncAfter(deadline: .now() + 5) {
                 print("sss \(NSStringFromClass(self.classForCoder))")
            }
            
        }
        
    }
   
}
extension NSObject{
    static func swizzlingload(){
        let mettod = class_getInstanceMethod(UIViewController.classForCoder(), #selector(UIViewController.viewWillAppear(_:)))
        let mettod2 = class_getInstanceMethod(UIViewController.classForCoder(), #selector(UIViewController.swizzlingViewWillAppear(_:)))
        method_exchangeImplementations(mettod!, mettod2!)
        
        
        let mettod1 = class_getInstanceMethod(UIViewController.classForCoder(), #selector(UIViewController.viewDidDisappear(_:)))
        let mettod11 = class_getInstanceMethod(UIViewController.classForCoder(), #selector(UIViewController.swizzlingViewDidDisappear(_:)))
        method_exchangeImplementations(mettod1!, mettod11!)
        
        
        let mettod3 = class_getInstanceMethod(UINavigationController.classForCoder(), #selector(UINavigationController.popViewController(animated:)))
        let mettod33 = class_getInstanceMethod(UINavigationController.classForCoder(), #selector(UINavigationController.swzzlingPopViewController(_:)))
        method_exchangeImplementations(mettod3!, mettod33!)
    }
}
extension UINavigationController{
    @objc func swzzlingPopViewController(_ animated: Bool) -> UIViewController?{
        let vc:UIViewController = swzzlingPopViewController(animated)!
        objc_setAssociatedObject(vc, &kHasBeenPoppedKey, true, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        return vc
    }
    
}
import UIKit

class PuthViewController: UIViewController {

    var timer:Timer?
    
    override func viewDidLoad() {
        super.viewDidLoad()
     
        print("viewDidLoad")
        test3()
    }
    
    func test3(){
        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { (timer) in
            print("qqq")
        })
    }
    
    override func didMove(toParent parent: UIViewController?) {
        if parent == nil {
            print("界面消失")
        }
    }
    
    deinit {
        timer?.invalidate()
        timer = nil
        print("\(self.classForCoder)")
    }
}


进入界面然后返回:

viewDidLoad
qqq
qqq
qqq
界面消失
qqq
qqq
qqq
qqq
qqq
qqq
sss test1.PuthViewController
PuthViewController

swift中 线程正在执行任务,会等待线程执行完毕之后才销毁对象。

你可能感兴趣的:(runtime 关联对象的简单运用)