在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一个子类而不是使用扩展是更正确的方法