needsDisplayForKey的思考

当我写一个自定义UI时遇到了class func needsDisplayForKey,完整定义如下

// QuartzCore/CALayer.h头文件中定义
    /* Method for subclasses to override. Returning true for a given
     * property causes the layer's contents to be redrawn when the property
     * is changed (including when changed by an animation attached to the
     * layer). The default implementation returns NO. Subclasses should
     * call super for properties defined by the superclass. (For example,
     * do not try to return YES for properties implemented by CALayer,
     * doing will have undefined results.) */

    class func needsDisplayForKey(key: String!) -> Bool

上述解释:如果对象继承自CALayer则可重写该方法并返回Bool(通常为true)通知该UI对象进行重绘(过程中调用几个draw方法)。

我写了一个使用例子来理理思路:如下

class A : CALayer{
    var distance : CGFloat = 0.0 //自定义member
    class func needsDisplayForKeyneedsDisplayForKey(key: String!) -> Bool{
        if key == "distance" {return true} // 在此处返回true告诉框架当我们定义的distance的值发生改变时需要重绘
        return super.needsDisplayForKey(key)
    }
    //other func ...
}

一切好像理所应当,但我感觉好像不是那么回事儿,第一我们都知道distance:CGFloat定义了以后,改变其值通常使用赋值 比如 instance.distance = 3.0
此处没有定义任何通知比如willSet,didSet 并通知重绘,它是如何实现的?
我查看了调用stack发现
needsDisplayForKey的思考_第1张图片
框架调用了CAObject_classInfo进行一个类似“反射”分析,又想起苹果在object-c2.0以后就使用了KVO(key-value-observation)技术 来跟踪key-value值就不明自清了。
所以在这里的needsDisplayForKeyneedsDisplayForKey方法也是提供了类似key-value-path给框架来跟踪该值(苹果为了代码好看些还真是下功夫)。

事情到这里还远远没结束呢,我又想那么框架又是如何调用needsDisplayForKeyneedsDisplayForKey方法的呢,起因是我随意写了这句话

override class func needsDisplayForKey(key: String!) -> Bool{
        if key == "distance" {return true}
        return super.needsDisplayForKey(key)
    }

然后我就注意到这个方法是类方法!不是实例方法,事实上(literally)上来说不能继承多态性!
看下例

class A{
    class func aM(){println("hallo a")}
}

class B:A{
    override class func aM(){println("hallo b")}
}

A.aM() // 结果hallo a
B.aM() // 结果hallo b

框架不能把自定义 A : CALayer 的类 typecast成CALayer的实例来调用,因为即使“覆盖了”也只是作为B类的类方法,不能通过A类来调用,而通常我们需要统一管理一类实例是把公共方法定义在父类中,使用 多态性 调用子类的重写函数,这与我们的编程习惯相左。

那我们分析下cocoa是怎么实现的,它首先对A:CALayer进行“反射”,分析A是否继承自CALayer,确认后解析出type类型,并调用其类方法needsDisplayForKeyneedsDisplayForKey,老玩家知道,这在Object-C时代是可以做到的,Object-C的NSObject实现了类似反射功能能通过String字符串获取成员变量和方法并调用,但在swift这个安全时代,至少我是没有找到类似的“强大功能”,所以使用swift是别想自己实现这个机制了。

那么话又说回来,为什么要劳神子的去实现类方法继承呢?
思来想去没有其他原因了,最后总结为:只为代码清晰和结构严谨
并且在typecast的时候保持类型完整,程序不会出错。
比如B:A ,那么当var a = B() as A时 因为 a 是A类型的,所以系统只会调用A的类方法,就不会因为B在重写方法中定义的某些“不良方法”而破坏A类的完整性。说的有点抽象,具体如下:
在这里举个例子:B继承A, B在类方法中定义了如果成员b:Float被修改则更新进度条,而被typecast成A以后,因为A中没有B定义的成员b,也没有进度条。如果使用多态性A就会调用B定义的方法,则会出错。调用只属于A类的类方法,就不会出错。
但是!这一机制同样可以由 new func …来解决。终止多态性的往下传递。所以我归结其为nextStep的程序猿喜欢这样干吧。

写了一个半小时,客官给个赏吧

你可能感兴趣的:(swift)