3

I would like to store a reference to a primitive type (Double, Int) in Swift, so that i one variable is changed, the other one is changed, too. Here is an example:

class MyClass {
    var value: Double?
}

var myValue = 1.0

var instance = MyClass()
instance.value = myValue    // <-- how to set a reference?

myValue = 2.0               // => I want instance.value to change to 2.0
instance.value = 3.0        // => I want myValue to change to 3.0

Is that possible?

adamsfamily
  • 1,746
  • 19
  • 37
  • 2
    Just *don't* expect Swift to work like this. Swift does not have references as C++ does (and even then this would be .. suspect); while there is [pointer support](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html) in Swift this still the *wrong* way write Swift code; Instead the container 'MyClass' instances *acts as* the "reference" through mutability and Object Sharing semantics. If you need another "reference" separation, create another wrapper type. – user2864740 Sep 17 '15 at 06:54
  • See http://stackoverflow.com/questions/26436932/how-to-pass-structure-by-reference for how to create a generic "Box" or "Holder" or "Ref" type. – user2864740 Sep 17 '15 at 07:00
  • @user2864740: Thanks, I understand that pointers are a bad practice (with direct memory access) and the wrapper type will be probably the best solution. – adamsfamily Sep 17 '15 at 12:36

3 Answers3

2

You can use class-holder:

class Ref<T> {
  var value: T

  init(_ value: T) {
    self.value = value
  }
}

Or try to read about In-Out Parameters and maybe it can help you in some way:

In-Out Parameters

Variable parameters, as described above, can only be changed within the function itself. If you want a function to modify a parameter’s value, and you want those changes to persist after the function call has ended, define that parameter as an in-out parameter instead.

You write an in-out parameter by placing the inout keyword at the start of its parameter definition. An in-out parameter has a value that is passed in to the function, is modified by the function, and is passed back out of the function to replace the original value.

You can only pass a variable as the argument for an in-out parameter. You cannot pass a constant or a literal value as the argument, because constants and literals cannot be modified. You place an ampersand (&) directly before a variable’s name when you pass it as an argument to an inout parameter, to indicate that it can be modified by the function.

func swapTwoInts(inout a: Int, inout _ b: Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// prints "someInt is now 107, and anotherInt is now 3"
Arsen
  • 10,815
  • 2
  • 34
  • 46
  • Thanks for the example with the Wrapper Type. The inout parameters are not an option for me as I would like to bind class member variables that can be read and written later. – adamsfamily Sep 17 '15 at 12:39
1

I use this:

@dynamicMemberLookup @propertyWrapper public struct Inout<Value> {
    init(_ value: Value) {
        storage = .init(value: value)
    }

    private final class Storage {
        var value: Value

        init(value: Value) {
            self.value = value
        }
    }

    private let storage: Storage

    subscript<Subject>(dynamicMember keyPath: WritableKeyPath<Value, Subject>) -> Subject {
        get { storage.value[keyPath: keyPath] }
        nonmutating set { storage.value[keyPath: keyPath] = newValue }
    }

    public var wrappedValue: Value {
        get { storage.value }
        nonmutating set { storage.value = newValue }
    }
}

Example 1:

    struct Value {
        var n = 0
    }
    let container = Inout(Value())
    container.n = 69
    print(container.n) // 69

Example 2:

struct Example { 
    init(value: Inout<Int>) { 
        _value = value
    }
    
    @Inout var value: Int
    
    func performAction() { 
        value += 19
    }
}
let value = Inout(wrappedValue: 50)
let example = Example(value: value)
example.performAction()
print(value.wrappedValue) // 69
Arutyun Enfendzhyan
  • 1,612
  • 1
  • 12
  • 15
0

The closest thing in Swift I can think of like this is inout variables. They are allowed in Swift as a constructor argument (but saving them to a variable stops them from working):

class Demo {
    var value: Double

    init(inout value: Double) {
        value++
        self.value = value
    }
}

var value = 1.0
let demo = Demo(value: &value)
print(value) // 2.0

demo.value++
print(value) // 2.0

Thus, I don't believe the syntax you want is possible. However, maybe inout parameters might be a substitute if you can re-work the problem.

Kevin Sylvestre
  • 37,288
  • 33
  • 152
  • 232