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
}

先说结论:

  1. 前提是key(本例是 outputImage)要与其他的key绑定(进行KVC绑定)
  2. 返回能触发对应输入参数 key 的 其他key的集合。
  3. 根据测试发现 super.keyPathsForValuesAffectingValue 会收集到 input*** 形式的参数

例如上面的方法,当设置toneMap的值时,会出发filter的outputImage方法。
如果 返回的Set中不包含 “toneMap”, 则设置toneMap时不会触发outputImage

测试步骤:

  1. 创建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
    }
    
}
  1. 创建TestFilter2, 用于将TestFilter的 ’outputImage‘ 与TestFilter2 的 ’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
    }
    
}
  1. 绑定,并测试
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
    }

你可能感兴趣的:(CIFilter,iOS,开发,macOS开发)