Van Du Tran
Van Du Tran

Reputation: 6892

How to declare a variable holding a struct reference?

Having this:

struct Person {
   var name = "Noname"
}

class World {
   var person: Person!

   func changePersonName(newName: String) {
      person.name = newName
   }
}

let you = Person(name: "Adam")
let world = World()
world.person = you
world.changePersonName("Eve")

println(you.name) // not "Eve", still "Adam"

In my case, I want person.name to become "Eve".

My question is how do I make the person variable in World not a copy, but a reference that I can modify its value like an object reference?

Upvotes: 0

Views: 183

Answers (4)

egor.zhdan
egor.zhdan

Reputation: 4605

As s1ddok pointed out, you can use UnsafeMutablePointer:

struct Person {
    var name = "Noname"
}

class World {
    var person: UnsafeMutablePointer<Person>!

    func changePersonName(newName: String) {
        person.memory.name = newName
    }
}

var you = Person(name: "Adam")
var ptr = UnsafeMutablePointer<Person>.alloc(1)
ptr.initialize(you)
let world = World()
world.person = ptr
world.changePersonName("Eve")

print(ptr.memory.name)

Upvotes: 0

matt
matt

Reputation: 535989

As GoZoner has rightly said, if you want to have a side-effect of mutating a Person through some other reference, you need a class, not a struct. That is exactly one of the chief differences between a class and struct. A struct is a value type; a class is a reference type. Thus, starting with your example code and fixing it so that it actually compiles:

struct Person {
    var name = "Noname"
}
class World {
    var person: Person!
    func changePersonName(newName: String) {
        person.name = newName
    }
}
let you = Person(name: "Adam")
let world = World()
world.person = you
world.changePersonName("Eve")
print(you.name) // "Adam"
print(world.person.name) // "Eve"

So, you can see that you and world.person are two different instances of Person. They are not references to one and the same instance. That's usually regarded as a good thing, but if, for some reason, that's not what you want, then use a class:

class Person {
    var name = "Noname"
    init(name:String) {self.name = name}
}
class World {
    var person: Person!
    func changePersonName(newName: String) {
        person.name = newName
    }
}
let you = Person(name: "Adam")
let world = World()
world.person = you
world.changePersonName("Eve")
print(you.name) // "Eve"
print(world.person.name) // "Eve"

Upvotes: 1

s1ddok
s1ddok

Reputation: 4654

If you really want to have a reference to a struct then UnsafeMutablePointer is your choice, but I wouldn't recommend using it.

Upvotes: 0

GoZoner
GoZoner

Reputation: 70235

If you want a 'reference type', rather than a 'value type', then use a class, rather than a struct.

class Person {
  var name = "Noname"
}

class World {
  var person = Person()
  changePersonName (name: String) {
    person.name = name
  }
}

Upvotes: 2

Related Questions