import UIKit
var robGlobal = Player(name: "Rob", health: 10, energy: 10)
var matt = Player(name: "Matt", health: 5, energy: 10)
struct Player {
var name: String
var health: Int
var energy: Int
static let maxHealth = 10
mutating func restoreHealth() {
health = Player.maxHealth
}
func balance(_ x: inout Int, _ y: inout Int) {
let sum = x + y
x = sum / 2
y = sum - x
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//MARK1: -Conflicting Access to self in Methods
robGlobal.shareHealth(with: &matt)
robGlobal.shareHealth(with: &robGlobal) // NOT OK in compile time Error: //Overlapping accesses to 'robGlobal', but modification requires exclusive access; consider copying to a local variable
var robNewLocal = Player(name: "Rob", health: 10, energy: 10)
robNewLocal.shareHealth(with: &robNewLocal) // NOT OK in compile time
//MARK2: -Conflicting Access to properties in Methods
robGlobal.someFunction() // OK
robGlobal.anotherFunction() // NOT OK in Run Time Error: Thread 1: Simultaneous accesses to 0x108cc4050, but modification requires exclusive access
}
}
extension Player {
mutating func shareHealth(with teammate: inout Player) {
balance(&teammate.health, &health)
}
func someFunction() {
var robLocal = Player(name: "Rob", health: 10, energy: 10)
balance(&robLocal.health, &robLocal.energy) // OK
}
func anotherFunction() {
balance(&robGlobal.health, &robGlobal.energy) // NOT OK in Run Time
}
}
Run Code Online (Sandbox Code Playgroud)
我试图了解 Swift 中的内存安全,我在两种情况之间感到困惑。
正如我在方法部分标记的MARK1: -Conflicting Access to self是有道理的。两次写访问相互重叠。在运行之前编译器已经给了我错误:
'robGlobal' 的重叠访问,但修改需要独占访问;考虑复制到局部变量
问题一:好的,但是MARK2部分呢?Swift 编译器进行了一些优化来解决这里对 struct 的写访问?
苹果解释说明如下解决方案,但我不清楚。
编译器可以证明保留了内存安全,因为这两个存储的属性不会以任何方式交互。
问题二:通过使全局运行时问题解决。但我想知道如何?还有为什么它不适用于 MARK1 部分,为什么?
PS:苹果文档在这里
使用robGlobal.someFunction(),您可以调用 的shareHealth单独本地实例robLocal。显然在这种情况下不存在内存安全问题。
但是对于robGlobal.anotherFunction(),您将调用 的实例方法robGlobal,但随后传递另一个对相同的引用robGlobal到shareHealth,因此内存安全违规。
但这很好。这在功能上相当于内存安全检查保护您免受的其他尝试之一:
\nrobGlobal.shareHealth(with: &robGlobal) \nRun Code Online (Sandbox Code Playgroud)\n整个想法是与其他玩家分享健康状况。抛开内存安全检查不谈,与自己共享一个玩家\xe2\x80\x99s 生命值意味着什么?例如,您当前的健康状况是 11。然后您与自己 \xe2\x80\x9cshare\xe2\x80\x9d 一起使用。那么,您现在的健康状况是 5 吗?还是6?您的健康状况是 11,而在您与自己分享后,它现在的值变小了,这是否有意义?与自己分享的整个想法没有意义。\xe2\x80\x9c 内存安全\xe2\x80\x9d 检查可保护您免受此类滥用。
\n就我个人而言,我会
\n创建balance一个static方法,因为它只是执行 \xe2\x80\x9cbalancing\xe2\x80\x9d 两个整数值,而不对当前实例执行任何操作;
这也可能应该是私有的,因为不需要公开这个函数;和
\n因为您似乎想要 \xe2\x80\x9cshare health\xe2\x80\x9d 来平衡两个玩家之间的健康以及平衡给定玩家的健康和能量,所以我会编写这两个方法。
\n因此,我们最终得到如下结果:
\nrobGlobal.shareHealth(with: &robGlobal) \nRun Code Online (Sandbox Code Playgroud)\n然后你可以做类似的事情:
\nstruct Player {\n var name: String\n var health: Int\n var energy: Int\n\n static let maxHealth = 10\n}\n\n// MARK: - Interface\n\nextension Player {\n mutating func restoreHealth() {\n health = Player.maxHealth\n }\n\n mutating func shareHealth(with teammate: inout Player) {\n Self.balance(&teammate.health, &health)\n }\n\n mutating func balanceHealthAndEnergy() {\n Self.balance(&health, &energy)\n }\n}\n\n// MARK: - Private utility methods\n\nprivate extension Player {\n static func balance(_ x: inout Int, _ y: inout Int) {\n let sum = x + y\n x = sum / 2\n y = sum - x\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n这个新界面(shareHealth和balanceHeathAndEnergy)简化了界面。您可以在本地变量或属性(或全局变量,如果您确实愿意的话)上调用它们;但使用全局变量通常是一个坏主意。但你永远不会shareHealth和自己在一起,现在这balance是私人的,它可以最大限度地减少你问题中概述的滥用。
FWIW,我不会将这些测试方法作为实例方法,Player因为它们不会对当前实例执行任何操作。您可以将它们设为静态方法。或者你可以在你的模型(或测试或其他什么)中让它们成为方法。Player但它们作为实例方法没有意义。
| 归档时间: |
|
| 查看次数: |
75 次 |
| 最近记录: |