【问题标题】:Accessor gives the wrong value in Swift 1.2/2.0 Release build only访问器仅在 Swift 1.2/2.0 发布版本中给出错误值
【发布时间】:2015-09-12 00:23:36
【问题描述】:

我在我的代码中发现了一个非常奇怪的错误,它只发生在发布版本中。对我来说,这看起来像是一个 Swift 错误,但请告诉我你的想法。

import Foundation

enum Level : Int {
    case
    Bad     = 0,
    Normal  = 1,
    Good    = 2,
    Superb  = 3
}

struct Attribute : Printable {
    var x : Level = .Normal
    var y : Level = .Normal
    var z : Level = .Normal
    var w : Level = .Normal

    var description : String {
        return "(\(x.rawValue), \(y.rawValue), \(z.rawValue), \(w.rawValue))"
    }

    func toString() -> String {
        return description
    }
}


var AccessorBugTestSingleton : AccessorBugTest!

class AccessorBugTest {

    let index       : Int
    var attributes  : [Attribute] = []
    var todaysAttributes : Attribute {
        get {
            let r = attributes[index]
            println("today: \(r)")
            return r
        }
    }
    var initialText : String = ""
    // selection for key
    var states  : [String:Int] = ["x": 0, "y": 0, "z": 0, "w": 0]
    var descriptions  : [String:Int] = ["a": 0, "b": 0, "c": 0, "d": 0]


    init() {
        index = 10
        for i in 1...31 {
            var att = Attribute(x: .Superb, y: .Superb, z: .Superb, w: .Superb)
            attributes.append(att)
        }

        let attribs = todaysAttributes
        initialText = "\(attribs)"
        println("init: \(attribs), \(self.attributes[index])")
    }

}

当 AccessorBugTest 被实例化时,它应该打印

init: (3, 3, 3, 3), (3, 3, 3, 3)

但在 Release 版本中它会打印出来,

init: (3, 0, 0, 0), (3, 3, 3, 3)

如果我删除未使用的属性statesdescriptions,那么问题就解决了,不知道为什么。此外,如果我使用 xyzw 整数而不是枚举,那么它会再次正常工作。

知道发生了什么吗?

我已将程序上传至:https://github.com/endavid/AccessorBugTest 它包含一个测试用例,如果您在 Release 配置中运行它会失败(转到 Program -> Scheme -> Edit Scheme,并将 Test 更改为 Release 而不是 Debug)。

我也下载了 Xcode 7.1 beta,在 Swift 2.0 中试过,问题依旧存在 :(

【问题讨论】:

  • 抱歉,我忘记推送更改了。这只是我在这张票中输入的代码。如果您在 Xcode 7.1 中加载代码,可以直接将其转换为 Swift 2.0,但我在 github 中使用 Swift 2.0 代码创建了一个分支,github.com/endavid/AccessorBugTest/tree/swift2
  • 我想如果我在 Xcode 7.1 和 iPhone6 模拟器 iOS9 下运行,代码将使用 Swift 2.0 运行。不是这样吗?我合并了您的拉取请求,但仍然失败。我需要在 Xcode 的某处选择“Swift 2”吗?我无法获得 Xcode 7 GM atm,但无论如何,我更担心 Swift 1.2,因为我必须修复我已经为 iOS8 发布的应用程序。我可以修复这种特殊情况,但我需要知道 Swift 1.2 中是否存在错误,究竟是什么导致它无法在代码中的任何地方避免这种情况并在 Swift 1.2 中提交我的应用程序的修复。
  • 好的,我终于可以重现这个错误了。我有一个不需要你改变你的架构的解决方法——反正不是很多。 :)
  • 也许这是 Xcode 7.1 beta 2 中修复的问题:“修复了打印某些枚举会将所有非有效负载情况报告为第一个非有效负载情况的错误。(22192074)”跨度>
  • 我在最新的稳定 Xcode 7.1 和 Swift 2.1 中验证了该错误已得到修复 :) 我已经更新了 github 存储库中的 README 文件。我会把代码留在那里以供参考。

标签: swift


【解决方案1】:

我认为你发现了一个错误。一个非常有趣的错误。

我有一个解决方法给你:让 Attribute 成为一个类而不是一个结构。它仍然是一个值类,所以开销会很低。您将必须给它一个初始化器,它执行 struct memberwise 初始化器所做的事情。当你这样做时,你会发现整个问题都消失了。

编辑:我想到了一个更好的解决方法:不要将 Attribute 设为一个类,而是将 Level 设为 @objc 枚举。

编辑: OP 报告说此错误已在 Swift 2.1 中修复。

【讨论】:

  • 因此您可以从中看出我假设该错误与枚举结构的复制方式有关。但是我对这个假设并没有很努力。我只是尝试了一些东西,直到找到解决方法。
  • 谢谢!该解决方法在 Swift 1.2 中也很好 :) 我将其更改为 class 并添加了一个构造函数 init(x: Level, y: Level, z: Level, w: Level) 现在它可以工作了。几天前我向 Apple 提交了一个错误报告,#22673382,但我还没有得到任何回复。我希望我们能就这个问题得到一些好的解释......
  • 我是个白痴。或者至少直到现在,当我想到一个更好的解决方法时。这里的理论是问题的根源在于枚举存储的性质;将枚举标记为@objc 会将存储更改为更像简单的 Int 存储,正如您已经说过的那样,它可以正常工作。 (我猜非@objc 枚举使用的东西更像位域;无论如何,如果我在设计语言,我会这样做。)
  • 哦,是的,这是最简单的解决方法 :) 为了安全起见,我想我会用当前版本的 @objc 枚举替换我的应用程序中的所有枚举。谢谢!
  • 我知道你会喜欢的。 :) 请注意,只有 Int-raw-value 枚举可以是 @objc 枚举。
猜你喜欢
  • 1970-01-01
  • 2016-01-31
  • 2014-10-16
  • 2016-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-05
  • 1970-01-01
相关资源
最近更新 更多