次の使用例を検討してください。
一部のゲームのモデルでは、Player
クラスがあります。それぞれPlayer
にunowned let opponent: Player
対戦相手を表す があります。これらは常にペアで作成され、 aはオプションではないため、Player
常に a が必要opponent
です。ただし、これをモデル化するのは非常に困難です。1 人のプレイヤーをもう 1 人のプレイヤーより先に作成する必要があり、最初のプレイヤーは 2 番目のプレイヤーが作成されるまで対戦相手を持たないからです!
いくつかの醜いハッキングを通じて、私はこの解決策を思いつきました:
class Player {
private static let placeholder: Player = Player(opponent: .placeholder, name: "")
private init(opponent: Player, name: String) {
self.opponent = opponent
self.name = name
}
unowned var opponent: Player
let name: String
class func getPair(named names: (String, String)) -> (Player, Player) {
let p1 = Player(opponent: .placeholder, name: names.0)
let p2 = Player(opponent: p1, name: names.1)
p1.opponent = p2
return (p1, p2)
}
}
let pair = Player.getPair(named:("P1", "P2"))
print(pair.0.opponent.name)
print(pair.1.opponent.name)
これは非常にうまく機能します。しかし、私はopponent
定数に変わるのに苦労しています。1 つの解決策は、 private に裏打ちされたopponent
なしで計算されたプロパティを作成することですが、これは避けたいと思います。set
var
Swift ポインターを使ってハッキングを試みたところ、次のようになりました。
class func getPair(named names: (String, String)) -> (Player, Player) {
var p1 = Player(opponent: .placeholder, name: names.0 + "FAKE")
let p2 = Player(opponent: p1, name: names.1)
withUnsafeMutablePointer(to: &p1) {
var trueP1 = Player(opponent: p2, name: names.0)
$0.moveAssign(from: &trueP1, count: 1)
}
return (p1, p2)
}
しかし、これはセグメンテーション違反を引き起こします。さらに、 を使用してデバッグすると、が初期化lldb
された直後に次のことがわかります。p1
(lldb) p p1
(Player2.Player) $R3 = 0x0000000101004390 {
opponent = 0x0000000100702940 {
opponent = <uninitialized>
name = ""
}
name = "P1FAKE"
}
しかし、関数の最後に、lldb は次のように表示します。
(lldb) p p1
(Player2.Player) $R5 = 0x00000001010062d0 {
opponent = 0x00000001010062a0 {
opponent = 0x0000000101004390 {
opponent = 0x0000000100702940 {
opponent = <uninitialized>
name = ""
}
name = "P1FAKE"
}
name = "P2"
}
name = "P1"
}
(lldb) p p2
(Player2.Player) $R4 = 0x00000001010062a0 {
opponent = 0x0000000101004390 {
opponent = 0x0000000100702940 {
opponent = <uninitialized>
name = ""
}
name = "P1FAKE"
}
name = "P2"
}
したがって、p1
正しく を指していますp2
が、p2
それでも古い を指していp1
ます。しかも、p1
実際に住所が変わった!
私の質問は 2 つあります。
相互の非オプション参照のこの構造を作成するための、よりクリーンで「迅速な」方法はありますか?
UnsafeMutablePointer
そうでない場合、上記のコードが機能しない Swift の s などについて、私は何を誤解していますか?