KVCメソッド:keyPathsForValuesAffectingValueForKey:CIFilterでの応用


KVCメソッド:keyPathsForValuesAffectingValueForKey:CIFilterでの応用

/// KVC,   key    key 。
override class func keyPathsForValuesAffectingValue(forKey key: String) -> Set<String> {
    //   super.keyPathsForValuesAffectingValue   input***  
    var supSet = super.keyPathsForValuesAffectingValue(forKey: key)

    // KVC  ,  "toneMap",   ""outputImage""
    if key == "outputImage" {
        supSet.insert("toneMap")
    }
    return supSet
}

結論を先に言います.
  • は、key(本例ではoutputImage)が他のkeyとバインド(KVCバインド)することを前提とする
  • である.
  • は、対応する入力パラメータkeyをトリガできる他のkeyのセットを返す.
  • 試験によりsuperを発見した.keyPathsForValuesAffectingValueはinput***形式のパラメータ
  • を収集します.
    たとえば、上記の方法では、toneMapの値を設定すると、filterのoutputImageメソッドが出発します.返されたSetに「toneMap」が含まれていない場合、toneMapの設定時にoutputImageはトリガーされません.

    テスト手順:

  • TestFilter
  • の作成
    import Cocoa
    class TestFilter: CIFilter {
        @objc dynamic var inputImage: CIImage?
        @objc dynamic var inputWidth: Double = 0
        
        @objc dynamic var toneMap: Double = 0
        @objc dynamic var inputToneMap: Double = 0
        var inputToneMap2: Double = 0
        
        /// KVC,   key    key 。
        override class func keyPathsForValuesAffectingValue(forKey key: String) -> Set<String> {
            //   super.keyPathsForValuesAffectingValue   input***  
            var supSet = super.keyPathsForValuesAffectingValue(forKey: key)
    
            // KVC  ,  "inputWidth",   ""outputImage""
            if key == "outputImage" {
                supSet.insert("toneMap")
            }
            return supSet
        }
        
        override var attributes: [String: Any] {
            return [
                kCIAttributeFilterDisplayName: "TestFilter", // filter name
                
                "inputImage": [kCIAttributeIdentity     : 0,
                               kCIAttributeClass        : "CIImage",
                               kCIAttributeDisplayName  : "Image",
                               kCIAttributeType         : kCIAttributeTypeImage],
                "inputWidth" : [kCIAttributeIdentity   : 0,
                                kCIAttributeClass       : "NSNumber",
                                kCIAttributeDefault     : 0,
                                kCIAttributeDisplayName : "inputWidth",
                                kCIAttributeType        : kCIAttributeTypeScalar],
                "toneMap" : [kCIAttributeIdentity   : 0,
                             kCIAttributeClass       : "NSNumber",
                             kCIAttributeDefault     : 0,
                             kCIAttributeDisplayName : "toneMap",
                             kCIAttributeType        : kCIAttributeTypeScalar],
                "inputToneMap" : [kCIAttributeIdentity   : 0,
                                  kCIAttributeClass       : "NSNumber",
                                  kCIAttributeDefault     : 0,
                                  kCIAttributeDisplayName : "inputToneMap",
                                  kCIAttributeType        : kCIAttributeTypeScalar],
                "inputToneMap2" : [kCIAttributeIdentity   : 0,
                                   kCIAttributeClass       : "NSNumber",
                                   kCIAttributeDefault     : 0,
                                   kCIAttributeDisplayName : "inputToneMap2",
                                   kCIAttributeType        : kCIAttributeTypeScalar]]
        }
        
        override var outputImage: CIImage? {
            let result = inputImage?.transformed(by: .init(scaleX: 0.2, y: 0.2))
            return result
        }
        
    }
    
  • TestFilter 2を作成し、TestFilterの'outputImage'をTestFilter 2の'inputImage'にバインドする
  • import Cocoa
    
    class TestFilter2: CIFilter {
        @objc dynamic var inputImage: CIImage?
        override var attributes: [String: Any] {
            return [
                kCIAttributeFilterDisplayName: "TestFilter2", // filter name
                
                "inputImage": [kCIAttributeIdentity     : 0,
                    kCIAttributeClass        : "CIImage",
                    kCIAttributeDisplayName  : "Image",
                    kCIAttributeType         : kCIAttributeTypeImage]]
        }
        
        override var outputImage: CIImage? {
            let result = inputImage?.transformed(by: .init(scaleX: 0.2, y: 0.2))
            return result
        }
        
    }
    
  • バインドし、
  • をテストします.
    func testFilterChain() {
            let testF1 = TestFilter.init()
            let testF2 = TestFilter2.init()
            //   TestFilter2   ”inputImage“   TestFilter   ”outputImage“ 
            testF2.bind(NSBindingName(rawValue: "inputImage"), to: testF1, withKeyPath: kCIOutputImageKey, options: nil)
    
    		//  ,  TestFilter   outputImage
            testF1.inputWidth = 100.0
            testF1.setValue(19.0, forKey: "inputWidth")
            testF1.toneMap = 0.2
    
            let t1OutImg = testF1.outputImage
        }