Consider the following use case:
In a model for some game, you have a Player class. Each Player has an unowned let opponent: Player which represents the opponent they are playing against. These are always created in pairs, and a Player must always have an opponent since it is non-optional. However, this is very difficult to model, since one player must be created before the other, and the first player will not have an opponent until after the second one is created!
Through some ugly hacking, I came up with this solution:
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)
Which works quite well. However, I am having trouble turning opponent into a constant. One solution is to make opponent a computed property without a set, backed by a private var, but I'd like to avoid this.
I attempted to do some hacking with Swift pointers, and came up with:
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)
}
But this gives a segfault. Furthermore, when debugging with lldb, we can see that just after p1 is initialized, we have:
(lldb) p p1
(Player2.Player) $R3 = 0x0000000101004390 {
  opponent = 0x0000000100702940 {
    opponent = <uninitialized>
    name = ""
  }
  name = "P1FAKE"
}
But at the end of the function, lldb shows this:
(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"
}
So p1 correctly points to p2, but p2 still points to the old p1. What's more, p1 has actually changed addresses!
My question is two-fold:
- Is there a cleaner, more 'Swifty' way to create this structure of mutual non-optional references? 
- If not, what am I misunderstanding about - UnsafeMutablePointers and the like in Swift that makes the above code not work?
 
     
     
     
    