<commit_before>//
//  NSObjectExt.swift
//  YJCocoa
//
//  HomePage:https://github.com/937447974/YJCocoa
//  YJ技术支持群:557445088
//
//  Created by 阳君 on 2019/5/29.
//  Copyright © 2016-现在 YJCocoa. All rights reserved.
//

import UIKit

/// KVO 回调
public typealias YJKVOBlock = (_ oldValue: Any?, _ newValue: Any?) -> Void

private class YJKeyValueObserver : NSObject  {
    
    weak var observer: AnyObject?
    var kvoBlock: YJKVOBlock!
    
    init(_ observer: AnyObject, kvoBlock: @escaping YJKVOBlock) {
        super.init()
        self.observer = observer
        self.kvoBlock = kvoBlock
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if self.observer != nil {
            self.kvoBlock(change?[NSKeyValueChangeKey.oldKey], change?[NSKeyValueChangeKey.newKey])
        }
    }
    
}

//MARK: KVO
public extension NSObject {
    
    /// 添加 KVO 监听
    @objc
    func addObserver(_ observer: AnyObject, forKeyPath keyPath: String, kvoBlock: @escaping YJKVOBlock) {
        let kvoArray = self.kvoArray(keyPath: keyPath)
        for item in kvoArray {
            let kvoItem = item as! YJKeyValueObserver
            if observer.isEqual(kvoItem.observer) {
                kvoItem.kvoBlock = kvoBlock
                return
            }
        }
        let kvo = YJKeyValueObserver(observer, kvoBlock: kvoBlock)
        kvoArray.add(kvo)
        self.addObserver(kvo, forKeyPath: keyPath, options: [.old, .new], context: nil)
    }
    
    /// 移除 KVO 监听
    @objc func removeObserverBlock(_ observer: NSObject, forKeyPath keyPath: String?) {
        if keyPath == nil {
            for key in self.yj_kvoDictionary.allKeys {
                self.removeObserverBlock(observer, forKeyPath: key as? String)
            }
        } else {
            for item in self.kvoArray(keyPath: keyPath!) {
                let kvoItem = item as! YJKeyValueObserver
                if kvoItem.observer != nil, observer.isEqual(kvoItem.observer) {
                    self.removeObserver(kvoItem, forKeyPath: keyPath!)
                    kvoItem.observer = nil
                    return
                }
            }
        }
    }
    
    private dynamic var yj_kvoDictionary: NSMutableDictionary {
        get {
            let key : UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "yj_kvoDictionary".hashValue)
            guard let kvoDict = objc_getAssociatedObject(self, key) as? NSMutableDictionary else {
                let kvoDict = NSMutableDictionary()
                objc_setAssociatedObject(self, key, kvoDict, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
                return kvoDict
            }
            return kvoDict
        }
        set {
            let key : UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "yj_kvoDictionary".hashValue)
            objc_setAssociatedObject(self, key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }<commit_msg>feat: 方法扩展<commit_after>//
//  NSObjectExt.swift
//  YJCocoa
//
//  HomePage:https://github.com/937447974/YJCocoa
//  YJ技术支持群:557445088
//
//  Created by 阳君 on 2019/5/29.
//  Copyright © 2016-现在 YJCocoa. All rights reserved.
//

import UIKit

/// KVO 回调
public typealias YJKVOBlock = (_ oldValue: Any?, _ newValue: Any?) -> Void

private class YJKeyValueObserver : NSObject  {
    
    weak var observer: AnyObject?
    var kvoBlock: YJKVOBlock!
    
    init(_ observer: AnyObject, kvoBlock: @escaping YJKVOBlock) {
        super.init()
        self.observer = observer
        self.kvoBlock = kvoBlock
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if self.observer != nil {
            self.kvoBlock(change?[NSKeyValueChangeKey.oldKey], change?[NSKeyValueChangeKey.newKey])
        }
    }
    
}

//MARK: KVO
public extension NSObject {
    
    /// 添加 KVO 监听
    @objc
    func addObserver(_ observer: AnyObject, forKeyPath keyPath: String, kvoBlock: @escaping YJKVOBlock) {
        let kvoArray = self.kvoArray(keyPath: keyPath)
        for item in kvoArray {
            let kvoItem = item as! YJKeyValueObserver
            if observer.isEqual(kvoItem.observer) {
                kvoItem.kvoBlock = kvoBlock
                return
            }
        }
        let kvo = YJKeyValueObserver(observer, kvoBlock: kvoBlock)
        kvoArray.add(kvo)
        self.addObserver(kvo, forKeyPath: keyPath, options: [.old, .new], context: nil)
    }
    
    /// 移除 KVO 监听
    @objc func removeObserverBlock(_ observer: NSObject, forKeyPath keyPath: String? = nil) {
        if keyPath == nil {
            for key in self.yj_kvoDictionary.allKeys {
                self.removeObserverBlock(observer, forKeyPath: key as? String)
            }
        } else {
            for item in self.kvoArray(keyPath: keyPath!) {
                let kvoItem = item as! YJKeyValueObserver
                if kvoItem.observer != nil, observer.isEqual(kvoItem.observer) {
                    self.removeObserver(kvoItem, forKeyPath: keyPath!)
                    kvoItem.observer = nil
                    return
                }
            }
        }
    }
    
    private dynamic var yj_kvoDictionary: NSMutableDictionary {
        get {
            let key : UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "yj_kvoDictionary".hashValue)
            guard let kvoDict = objc_getAssociatedObject(self, key) as? NSMutableDictionary else {
                let kvoDict = NSMutableDictionary()
                objc_setAssociatedObject(self, key, kvoDict, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
                return kvoDict
            }
            return kvoDict
        }
        set {
            let key : UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "yj_kvoDictionary".hashValue)
            objc_setAssociatedObject(self, key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
{'fraction_non_alphanumeric': 0.08980944490472245, 'fraction_numerical': 0.009610604805302403, 'mean_word_length': 2.1081359423274972, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5904858', 'n_tokens_mistral': 2000, 'n_tokens_neox': 1909, 'n_words': 410}