【问题标题】:Simultaneous accesses to 0x14572f2a0, but modification requires exclusive access同时访问0x14572f2a0,但修改需要独占访问
【发布时间】:2021-09-19 13:57:03
【问题描述】:

我正在关注“Swift 5 中的设计模式”一书中的示例代码。该示例适用于状态模式部分。

我收到内存访问错误:“同时访问 0x14572f2a0,但修改需要独占访问。”当我尝试运行代码时。

我不确定发生了什么...提前致谢!

代码:

import Foundation

public final class ATM {
    
    fileprivate var state: ATMState = IdleState()
    
    public func enter(pin: String) {
        state = EnterPinState(context: self)
        state.validate(pin: pin)
    }
    
    public func withdraw(amount: Float) -> Bool {
        return state.withdraw(amount: amount)
    }
}

fileprivate protocol ATMState {
    func validate(pin: String)
    mutating func withdraw(amount: Float) -> Bool
    func transactionCompleted(success:Bool)
}

extension ATMState {
    func validate(pin:String) {
        print("not implemented")
    }
    mutating func withdraw(amount: Float) -> Bool {
        print("not implemented")
        return false
    }
    func transactionCompleted(success:Bool) {
        print("not implemented")
    }
}

fileprivate struct IdleState: ATMState {
    
}

fileprivate struct EnterPinState: ATMState {
    
    let context: ATM
    
    func validate(pin: String) {
        guard pin == "1234" else {
            print("wrong pin")
            context.state = TransactionCompleteState(context:context)
            context.state.transactionCompleted(success: false)
            return
        }
        print("pin ok")
        context.state = WithdrawState(context: context)
    }
}

fileprivate struct TransactionCompleteState: ATMState {
    let context: ATM
    
    func transactionCompleted(success: Bool) {
        var statusMessage = success ? "Transaction complete..." : "Transaction failed..."
        print(statusMessage)
        context.state = IdleState()
    }
}

fileprivate struct WithdrawState: ATMState {
    var context: ATM
    var availableFunds: Float = 1000
    
    init(context: ATM) {
        self.context = context
    }
    
    mutating func withdraw(amount: Float) -> Bool {
        print("Withdraw $\(amount)")
        guard amount > 0 && availableFunds >= amount else {
            print("invalid")
            context.state = TransactionCompleteState(context: context)
            context.state.transactionCompleted(success: false)
            return false
        }
        availableFunds -= amount
        context.state = TransactionCompleteState(context: context)
        context.state.transactionCompleted(success: true)
        return true
    }
}

let atm = ATM()
atm.enter(pin:"1234")
atm.withdraw(amount: 10)

【问题讨论】:

    标签: swift


    【解决方案1】:

    这就是您在操场上测试代码所得到的——没有调试器!如果您在实际应用中尝试该代码,调试器会准确告诉您问题所在。

    问题出在这里:

    public func withdraw(amount: Float) -> Bool {
        return state.withdraw(amount: amount) // <-- *
    }
    

    withdraw 状态的withdraw 方法设置它的context 的state 属性,这是这个ATM 实例。所以对state.withdraw的调用意味着我们直接改变这个ATM的状态值,通过用不同的状态对象替换它,并且调用它的改变方法 withdraw,一步到位。你不能这样做,因为对结构的属性和对整个结构的引用的双重突变是不连贯的。您必须分阶段进行,如下所示:

    public func withdraw(amount: Float) -> Bool {
        // fetch
        var theState = self.state
        // mutate
        return theState.withdraw(amount: amount)
    }
    

    另一种方法是使所有状态类型类而不是结构。与结构不同,类是可变的。然而,这需要更多的重写,因此留给读者作为练习。

    【讨论】:

    • OP,请注意小幅修正;对此感到抱歉。
    • 您能否详细说明为什么这是访问冲突?我没看到。我们在一个实例成员上调用一个变异函数。 “我们都获取状态并调用其变异方法撤消” IDK 您所说的“获取”究竟是什么意思,它与 var theState = self.state 中所做的有什么不同?
    • 是的,你完全正确,我会解决这个问题。谢谢你让我诚实。
    • 不是我的本意,很抱歉打断你的疯子,但我还是不明白。 state 在哪里被“替换”了?
    • 在撤回状态的withdraw函数中:context.state =... 整个事情的“深层”原因是使用context指向这个结构的所有者。看看该模式是如何工作的:每次调用 state 方法都可以用代表 ATM 下一阶段的不同状态替换状态。这是一个很酷的模式,但它遇到了访问冲突问题。
    猜你喜欢
    • 2019-01-11
    • 2018-03-07
    • 2019-05-06
    • 1970-01-01
    • 2018-02-21
    • 2019-10-28
    • 2018-02-17
    • 1970-01-01
    • 2018-01-07
    相关资源
    最近更新 更多