gpt4 book ai didi

swift - NSCopy GKGameModel 无法正确复制玩家对象

转载 作者:行者123 更新时间:2023-11-30 11:07:24 27 4
gpt4 key购买 nike

我正在尝试使用 swift NSCopy 来深度复制 GKGameModel 的对象,包括所有玩家及其钱包引用(包含代表现金的整数)。

使用 Swift Playgrounds,我尝试将 100 美元记入所有复制的玩家,但保持原始玩家对象完好无损。

但是,我注意到该代码也会影响原始玩家对象。

在较高的层次上,代码应该显示:

Game class, a GKGameModel
Player class, a GKPlayerModel
Wallet class, handles very basic player's Int transactions.

目标:

  • 复制游戏类别、所有玩家及其关联的钱包类别
  • 向复制的玩家赠送 100 美元。
  • 原来的玩家应该还有$0

代码如下:

// Uses Swift playground

import GameplayKit

class Game : NSObject, GKGameModel{
override var description: String {
return ("game: \(String(describing: self.players))")
}

// -- GKGameModel code follows --
var players: [GKGameModelPlayer]?
var activePlayer: GKGameModelPlayer?


func gameModelUpdates(for player: GKGameModelPlayer) -> [GKGameModelUpdate]? {
return nil
}

func unapplyGameModelUpdate(_ gameModelUpdate: GKGameModelUpdate) {
}


func apply(_ gameModelUpdate: GKGameModelUpdate) {

}

func setGameModel(_ gameModel: GKGameModel) {
guard let inputModel = gameModel as? Game else {
assertionFailure("No game model initialised")
return
}
guard let players = inputModel.players else {
assertionFailure("No players initialised")
return
}

self.activePlayer = inputModel.activePlayer
self.players = players
}

func copy(with zone: NSZone? = nil) -> Any {
print ("copying game obj!")
let copy = Game()
copy.setGameModel(self)
copy.players = self.players // if I do not include it, copy.players is nil
return copy
}
}

class Player : NSObject, NSCopying, GKGameModelPlayer {
override var description: String {
return ("name: \(name), cash: $\(cash), wallet: $\(wallet.balance)")
}

internal var playerId: Int = 0 {
didSet {
print ("Set playerId = \(self.playerId)")
}
}
var name: String
var cash : Int = 0

var wallet : Wallet = Wallet()

init(name: String) {
self.name = name
}

func copy(with zone: NSZone? = nil) -> Any {
print ("copying player!!") // this code is never reached
let copy = self
copy.wallet = self.wallet.copy(with: zone) as! Wallet
return copy
}
}

enum WalletError : Error {
case mustBePositive
case notEnoughFunds
}

fileprivate protocol WalletDelegate {
var balance : Int { get }
func credit(amount: Int) throws
func debit(amount: Int) throws
}

class Wallet : NSCopying, CustomStringConvertible, WalletDelegate {
public private(set) var balance: Int = 0

func credit(amount: Int = 0) throws {
try canCredit(amount: amount)
self.balance += amount
}

func debit(amount: Int = 0) throws {
try canDebit(amount: amount)
self.balance -= amount
}

func copy(with zone: NSZone? = nil) -> Any {
print ("copy wallet") // this code is never reached
let copy = Wallet()
return copy
}
}


extension Wallet {
private func canCredit(amount: Int) throws {
guard amount > 0 else {
throw WalletError.mustBePositive
}
}

private func canDebit(amount: Int) throws {
guard amount > 0 else {
throw WalletError.mustBePositive
}

guard self.balance >= amount else {
throw WalletError.notEnoughFunds
}
guard (self.balance - amount >= 0) else {
throw WalletError.notEnoughFunds
}
}
}

extension Wallet {
var description: String {
return ("Balance: $\(self.balance)")
}
}

let players : [GKGameModelPlayer] = [ Player.init(name: "Bob"), Player.init(name: "Alex"), Player.init(name: "John") ]
let game = Game()
game.players = players

func copyTheGame() {
let copiedGame = game.copy() as! Game

print ("BEFORE:")
print ("Original: \(String(describing: game))")
print ("Copied: \(String(describing: copiedGame))")
print ("----")

if let copiedPlayers = copiedGame.players {
for p in copiedPlayers as! [Player] {
do {
p.cash = 100 // try to manipulate a class variable.
try p.wallet.credit(amount: 100)
} catch let err {
print (err.localizedDescription)
break
}
}
}

print ("AFTER:")
print ("Original: \(String(describing: game))")
print ("Copied: \(String(describing: copiedGame))")
print ("----")
}

copyTheGame()

在我的输出中,我得到以下内容:

copying game obj!
BEFORE:
Original: game: Optional([name: Bob, cash: $0, wallet: $0, name: Alex, cash: $0, wallet: $0, name: John, cash: $0, wallet: $0])
Copied: game: Optional([name: Bob, cash: $0, wallet: $0, name: Alex, cash: $0, wallet: $0, name: John, cash: $0, wallet: $0])
----
AFTER:
Original: game: Optional([name: Bob, cash: $100, wallet: $100, name: Alex, cash: $100, wallet: $100, name: John, cash: $100, wallet: $100])
Copied: game: Optional([name: Bob, cash: $100, wallet: $100, name: Alex, cash: $100, wallet: $100, name: John, cash: $100, wallet: $100])
----

问题:

  • 玩家复制代码永远不会被命中
  • 钱包复制代码永远不会被击中
  • 存入的 100 美元同时影响原件和副本。

如何确保我所做的任何更改仅针对复制的游戏对象,而不是原始对象?

感谢

<小时/>

更新:

我已经能够通过循环遍历所有玩家对象来强制复制,但我不相信这是最好的方法。

如果我将游戏类中的复制函数更改为:

 func copy(with zone: NSZone? = nil) -> Any {
let copy = Game()

let duplicate = self.players?.map({ (player: GKGameModelPlayer) -> GKGameModelPlayer in
let person = player as! Player
let copiedPlayer = person.copy(with: zone) as! Player
return copiedPlayer
})

copy.players = duplicate

return copy
}

这也让我可以复制所有玩家对象;播放器和钱包类中的 copy() 函数受到攻击。

最佳答案

我已经能够通过强制复制引用对象、数组或子对象来解决该问题

即:

 func copy(with zone: NSZone? = nil) -> Any {
let copy = Game()

let duplicate = self.players?.map({ (player: GKGameModelPlayer) -> GKGameModelPlayer in
let person = player as! Player
let copiedPlayer = person.copy(with: zone) as! Player
return copiedPlayer
})

copy.players = duplicate

return copy
}

关于swift - NSCopy GKGameModel 无法正确复制玩家对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52554081/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com