【问题标题】:Gesture event interferes with property observer catching property in invalid state手势事件干扰属性观察者捕获处于无效状态的属性
【发布时间】:2016-04-19 20:26:25
【问题描述】:

我使用以下类来管理图像幻灯片列表并跟踪活动幻灯片:

class Slides
{
    var list: [String] = []
    var activeIndex: Int = 0
    {
        didSet
        {
            if activeIndex < 0
            {
                activeIndex = list.count - 1
            }
            else
            if activeIndex > list.count
            {
                activeIndex = 0
            }
        }
    }

    var active: String
    {
        get
        {
            return list[activeIndex]
        }
    }

    func next() -> Int
    {
        return activeIndex++
    }

    func prev() -> Int
    {
        return activeIndex--
    }
}

函数prev()next() 以循环方式给我上一张或下一张幻灯片 - 环绕到幻灯片列表的开头或结尾。

我正在使用activeIndex 属性观察器来防止设置无效索引。

在应用程序中,我使用滑动手势来显示下一张或上一张幻灯片。

@IBAction func onSwipeLeft(sender: AnyObject)
{
    slides.next()
    let slide = slides.active
    ...
}

@IBAction func onSwipeRight(sender: AnyObject)
{
    slides.prev()
    let slide = slides.active
    ...
}

它在大多数情况下运行良好,但偶尔来回滑动会在 active 属性 getter 中触发 array index out of range 异常。这意味着手势事件会中断并在将实际值设置为 activeIndex 和调用其观察者以防止 activeIndex 存储无效值之间执行代码。

问题是为什么会发生这种情况,解决方案是什么?

【问题讨论】:

    标签: ios swift swift2


    【解决方案1】:

    user3608334:s 上面的回答指出了导致运行时异常的一个错误,但我想我会就可能有价值的代码添加几点。


    ++-- 运算符将在 Swift 3 中弃用。

    关于它的当前使用,注意next()prev()方法中的return语句return activeIndex++return activeIndex--分别会返回activeIndex的当前值的副本先于 突变。

    // ...
    activeIndex = 1
    return activeIndex++ /* returns 1, activeIndex is set to 2 */
    

    可能next()prev() 函数不需要返回值,只需改变activeIndex,至少考虑到您在示例中如何调用它们。

    最后,请注意,如果计算属性只有一个 getter,那么您可以省略明确说明(并且只使用一组大括号)。


    总结上面的笔记,我们可以把你的课程写成:

    class Slides
    {
        var list: [String] = []
        var activeIndex: Int = 0 {
            didSet
            {
                if activeIndex < 0 {
                    activeIndex = list.count - 1
                }
                else if activeIndex >= list.count {
                    activeIndex = 0
                }
            }
        }
    
        var active: String {
            return list[activeIndex]
        }
    
        func next() // -> Int
        {
            activeIndex = activeIndex + 1
            // return activeIndex
        }
    
        func prev() // -> Int
        {
            activeIndex = activeIndex - 1
            // return activeIndex
        }
    }
    

    【讨论】:

    • 我刚刚注意到您的didSet 逻辑不正确。如果 activeIndex 值超出范围,则不应将其设置为旧值,而应环绕 - 如果它是 &lt;0,它应该变成 count-1,如果 &gt;=count 它应该变成 0 对我来说并不重要,但是对于未来的读者......
    • @DalijaPrasnikar 啊,我错过了,如果超出最后一张幻灯片,它应该连续滚动回开始,我的错(以为它是在结束/开始幻灯片停止)。会更新的,谢谢!
    【解决方案2】:

    这行代码中存在错误:

    if activeIndex > list.count
    

    应该是:

    if activeIndex >= list.count
    

    【讨论】:

    • @dfri 如果你的意思是我假设列表总是有元素,即使它看起来可能是空的,我已经涵盖了这部分。
    • @DalijaPrasnikar 或者我在这里只提一下:myIntVar++ 将在 Swift 3 中被弃用,以免将来破坏您的应用程序,您可能最好使用 @ 987654324@.
    • @dfri 谢谢,这应该不是什么大问题 :)
    • @DalijaPrasnikar 我明白了。在上面的示例中,我看到您的函数 prev()next() 返回一个未使用的整数。也许您知道这一点,但请务必小心如果您选择使用它,因为return myIntVar++ 将返回myIntVar:s 当前 值,并且只有在那之后增加它的价值。无论如何,只是关于++ 的注释:)
    • @dfri 谢谢。原始代码有两行,但是我在尝试跟踪并发错误时尝试为 SO 优化代码,并且错误仍然存​​在,代码已更改...我想我该休息一下了...
    猜你喜欢
    • 1970-01-01
    • 2016-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-15
    • 1970-01-01
    • 1970-01-01
    • 2017-10-16
    相关资源
    最近更新 更多