【问题标题】:Swift Optional sometimes crashes on device but not on simulator when checking nil检查 nil 时,Swift Optional 有时会在设备上崩溃,但不会在模拟器上崩溃
【发布时间】:2015-01-17 19:43:36
【问题描述】:

最奇怪的事情。我有两种以完全相同的方式使用可选枚举的方法。一个功能始终有效,无论是在设备中还是在模拟中。但是,第二种方法仅适用于模拟器,有时适用于设备。我很确定它“何时”起作用与我所做的测试的价值无关。例如,我总是先用 nil 值调用该方法,只是有时它会崩溃。

错误是 EXC_ARM_BREAKPOINT,不打印任何消息,并且堆栈跟踪没有帮助。即使在检查 nil 之后,调试器也会将选项的值显示为“Some”,这很奇怪,因为我无法打印它(尝试时崩溃)。

失败的代码:

class LevelElevenState: GameState {
     init(count: Int, var goalNumber: GameNumber?) { 
         super.init(stateType: .Normal)
         self.transition = {
            (actionDone: GameAction) -> GameState? in

            switch actionDone {
            case .Pressed(let number):

                if goalNumber == nil {  //FAILS HERE
                    goalNumber = number //OR HERE
                }

                if goalNumber == number {
                    self.delegate?.switchIndicators(true, lights: [GameNumber(rawValue: count)!])


                    if count < 5 {
                        let direction = GameDirection(rawValue: Int(arc4random()) % 2)!
                        let amount = Int(arc4random_uniform(98)) + 1
                        var nextRaw = number.rawValue
                        switch direction {
                        case .Up:
                            nextRaw = (nextRaw + amount) % 5
                        case .Down:
                            nextRaw = ((nextRaw - amount) % 5) + 5
                        }
                        let nextNumber = GameNumber(rawValue: nextRaw)

                        let phrase = "\(direction), \(amount)"
                        self.delegate?.speakPhrase(phrase)

                        return LevelElevenState(count: count + 1, goalNumber: nextNumber)
                    } else {
                        return GameState.goal()
                    }
                }else {
                    return GameState.mistake()
                }
            default:
                return nil
            }
        }
    }
}

class LevelEleven: GameStateLevel, GameStateLevelDelegate {

    override init() {
        super.init()
        levelDelegate = self
        index = 10
    }

    func initialState() -> GameState {
        return LevelElevenState(count: 1, goalNumber: nil)
    }
}

以下代码永远不会崩溃。我个人看不出有什么区别。

class LevelSevenState: GameState {
    var count = 0

    init(goal: Int, var goalNumber: GameNumber?) {

        super.init(stateType: .Normal)
        self.transition = {
            (actionDone: GameAction) -> GameState? in

            switch actionDone {
            case .Pressed(let number):
                if goalNumber == nil {
                    goalNumber = number
                }

                if goalNumber == number {
                    self.count++

                    if self.count == goal {
                        if let indicator = GameNumber(rawValue: goal) {
                            self.delegate?.switchIndicators(true, lights: [indicator])
                        }

                        if goal < 5 {
                            return LevelSevenState(goal: goal + 1, goalNumber: goalNumber)
                        } else {
                            return GameState.goal()
                        }
                    }else {
                        return nil
                    }
                }else {
                    return GameState.mistake()
                }
            default:
                return nil
            }
        }
    }
}

class LevelSeven: GameStateLevel, GameStateLevelDelegate {

    override init() {
        super.init()
        levelDelegate = self
        index = 6
    }

    func initialState() -> GameState {
        return LevelSevenState(goal: 1, goalNumber: nil)
    }
}

编辑:根据要求

enum GameNumber: Int {
    case One = 1
    case Two = 2
    case Three = 3
    case Four = 4
    case Five = 5

    init?(myRaw: Int) {
        if let fromRaw = GameNumber(rawValue: myRaw) {
            self = fromRaw
        }else {
            return nil
        }
    }

    init(color: GameColor) {
        switch color {
        case .Blue:
            self = .One
        case .Green:
            self = .Two
        case .Yellow:
            self = .Three
        case .Orange:
            self = .Four
        case .Red:
            self = .Five
        }
    }
}

【问题讨论】:

  • 在未连接调试器时是否运行?只是想知道您是否有触发的断点(可能是符号)。代码停止后能恢复还是崩溃了?
  • 这是一个崩溃,没有调试器也不行。
  • 你能添加 GameNumber 的定义和它引用的任何类/结构吗?
  • 添加了定义。

标签: ios swift


【解决方案1】:

是的,这就是 Int(arc4random()) 崩溃的部分。原因是arc4random() 返回UInt32,它可能(随机!)超过Int.max 并导致Int(...) 崩溃——正如here 所回答的那样。 有很多方法可以避免这种情况,例如,您可以先计算余数,然后将其传递给Int(...):

Int(arc4random() % 2)

或者你可以使用

Int(arc4random_uniform(2))

只要确保Int(...) 的参数在限制范围内! 干杯)

【讨论】:

    【解决方案2】:

    我发现了问题。调试如此困难的原因是该错误与我的想法无关。 XCode 在错误的线路上中断。这是导致错误的那一行:

    Int(arc4random()) % 2
    

    我不知道为什么会导致 swift 崩溃,但肯定是这样。如果有人对此问题有任何见解,我将很乐意接受解决该问题的答案。

    【讨论】:

    • 听起来是个不同的问题。
    • 我对 SO 的最佳实践不是很熟悉,所以我希望能得到一些关于如何处理这个问题的反馈。我是否应该删除这个具有误导性的问题,并创建一个人们更有可能通过搜索找到的新问题?
    • 你应该标记你自己的答案,或者上面描述这个更好的答案以及接受的答案。如果您还有其他问题,例如 swift 为什么会在此问题上崩溃,您应该打开另一个主题,也许在描述中带有指向该主题的链接。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-17
    • 2013-06-06
    • 1970-01-01
    • 1970-01-01
    • 2012-07-09
    • 2015-07-11
    • 1970-01-01
    相关资源
    最近更新 更多