解决Swift属性覆盖中的递归 [英] Resolve recursion in Swift property override

查看:92
本文介绍了解决Swift属性覆盖中的递归的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是Swift中针对UILabel的一个简单扩展,

Here's a simple extension in Swift, for 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,只需执行此操作

with a UILabel, simply do this

aLabel.change("hello there")

它将快速从旧文本过渡到新文本.没问题.

It will quickly blend from the old to the new text. No problem.

当然,如果我们可以编写此代码会更好...

Of course, it would be better if we could write this ...

aLabel.text = "hello there"

要做到这一点,只需使用新版本的".text"属性创建一个新的UILabel类.

To do that, just make a new UILabel class, with a new version of the ".text" property.

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

但是!它行不通:它陷入了无休止的循环.

But! It doesn't work: it goes in to an endless loop.

请注意change()扩展名中的"self.text":此时进入循环.

Notice the "self.text" in the change() extension: at that point it goes in to a loop.

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

(I also tried set { self.change(newValue!) } and it does not work.)

以下内容可以正常工作:

The following works perfectly:

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 })
                    })
            }
        }
    }

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

That's fine, but what am I doing wrong in the first version?

您如何编写setter才能成功使用.change扩展名?

How would you write the setter to successfully use the .change extension?

顺便说一句,对于任何在这里阅读的人来说,都是如何更全面地继承IBLabel的子类,您必须重写指定的初始化程序,并且,您需要保留本地的实时"文本版本,以便getter正确答复.在动画过程中,在设置文字之后.

By the way, for anyone reading here is how you would more fully subclass IBLabel, you have to override the designated initialiser, and, you'll need to keep a local "realtime" version of text so that the getter replies correctly during animations, immediately after you set the text.

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中分配新值时将调用您的递归,因为这将调用setter,后者将调用等等.

Your recursion is called when you use self.text= to assign a new value in your change extension method because this will call the setter, which calls change and so on.

在第二个示例中,避免了递归,因为可以从子类设置器中调用超类设置器.您的扩展名中没有此选项,因为您的代码正在作为UILabel的扩展名运行,因此没有要调用的超类设置器.

In your second example, you avoid recursion because you can call the superclass setter from your subclass setter. You don't have this option in your extension because your code is running as an extension to UILabel and therefore there is no superclass setter to call.

在这种情况下,可以说创建子类而不是使用扩展是更正确的方法

Arguably creating a subclass rather than using extension is the more correct approach in this instance anyway

这篇关于解决Swift属性覆盖中的递归的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆