Swift Optional有时在设备上崩溃,但在检查nil时不在模拟器上崩溃

时间:2015-01-15 16:02:06

标签: ios swift

最奇怪的事情。我有两种方法以完全相同的方式使用可选的枚举。在设备和模拟中,一个功能始终有效。但是,第二种方法仅适用于模拟器,而有时适用于设备。我很确定它“何时”起作用与我所做的测试值无关。例如,我总是先用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
        }
    }
}

2 个答案:

答案 0 :(得分:1)

我发现了问题。调试如此困难的原因是错误与我的想法无关。 XCode打破了错误的界限。这是造成错误的一行:

Int(arc4random()) % 2

我不确切地知道为什么会迅速崩溃,但这绝对是它。如果有人对这个问题有任何见解,我会很乐意接受一个解决这个问题的答案。

答案 1 :(得分:1)

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

Int(arc4random() % 2)

或者您可以使用

Int(arc4random_uniform(2))

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