在Swift属性重写中解决recursion

这里是Swift中的简单扩展,对于UILabel,

let dur=0.1 // (set to say 2.0 to see the effect more clearly) extension UILabel { func change(s:String)->() { print("attempting 'change' with \(s)") UIView.animateWithDuration( dur, animations: { self.alpha = 0.2 }, completion: { _ in self.text = s ///CCC UIView.animateWithDuration( dur, animations: { self.alpha = 1.0 }) }) } } 

用UILabel,只要做到这一点

 aLabel.change("hello there") 

它会很快从旧的文本混合到新的文本。 没问题。

当然,如果我们能写这个会更好…

 aLabel.text = "hello there" 

要做到这一点,只需要新build一个“.text”属性就可以创build一个新的UILabel类。

 class CoolLabel:UILabel { override var text:String? { get { return super.text } set { super.change(newValue!) } //PROBLEM! AAA } } 

但! 它不工作:它进入一个无限循环。

注意change()扩展中的“self.text”:在这一点上,它进入一个循环。

(我也尝试set { self.change(newValue!) } ,它不起作用。)

以下作品完美:

 class TOLabel:UILabel { override var text:String? { get { return super.text } set { UIView.animateWithDuration( dur, animations: { self.alpha = 0.2 }, completion: { _ in super.text = newValue //BBB UIView.animateWithDuration( dur, animations: { self.alpha = 1.0 }) }) } } } 

这很好,但是我在第一个版本中做错了什么?

你将如何编写setter来成功使用.change扩展名?


顺便说一下,对于读这里的任何人来说,你将如何更完全地inheritanceIBLabel,你必须重写指定的初始化程序,并且需要保留一个本地的“实时”版本的文本,以便getter在animation过程中正确回复,在您设置文本后立即。

 class TOLabel:UILabel { private var _text:String? required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) self._text = super.text; } override var text:String? { get { return self._text } set { self._text = newValue; UIView.animateWithDuration( dur, animations: { self.alpha = 0.2 }, completion: { _ in super.text = self._text UIView.animateWithDuration( dur, animations: { self.alpha = 1.0 }) }) } } } 

当您使用self.text=在您的change扩展方法中分配一个新值时,将调用recursion,因为这将调用setter,该setter调用change等等。

在你的第二个例子中,你避免了recursion,因为你可以从你的子类setter中调用超类setter。 你的扩展中没有这个选项, 因为你的代码是作为UILabel的扩展运行的,所以不需要超类设置器来调用。

无论如何,在这种情况下,可靠地创build一个子类而不是使用扩展是更正确的方法