Can I create a reference to a variable in Swift?
There are no references for variables, but you can simulate the behavior with a Computed Variable.
Computed variables calculate their values instead of storing them, and they are written in the same way as computed properties. By writing the get
and set
to read and write the original variable, you can simulate the behavior you want.
override func viewDidAppear(_ animated: Bool) {
var reference: Bool {
get { return test.shared.changeMe }
set { test.shared.changeMe = newValue }
}
reference = true
print("Reference: " + String(reference))
test.shared.printValue()
}
Note: If you need access to reference
outside of viewDidAppear
, then declare it as a computed property on the class instead (just move it outside of the function).
Change value of variable by reference
You can accomplish this using a ReferenceWritableKeyPath
.
What is a
ReferenceWritableKeyPath
?
Think of it as a precise description of a property in a class
or struct
. A real world example would be The Empire State Building instead of the address which would be 20 W 34th St, New York, NY 10001. You could tell either one to a cab driver and she could take you there.
A ReferenceWritableKeyPath
is a generic type. You need to specify the class
or struct
name and the type of the variable you will be accessing. So your choice
variable would be a ReferenceWritableKeyPath<YourClass,ColoresDeSalidas>
.
Here is a standalone example:
enum ColoresDeSalidas : String {
case Negra
case Blanca
case Roja
case Azul
case Verde
}
class Foo {
var backTees = false
var option = 1
var colorHcpBackTees1: ColoresDeSalidas = .Negra
var colorHcpBackTees2: ColoresDeSalidas = .Blanca
var colorHcpFrontTees1: ColoresDeSalidas = .Roja
var colorHcpFrontTees2: ColoresDeSalidas = .Blanca
var choice: ReferenceWritableKeyPath<Foo,ColoresDeSalidas> {
if backTees && option == 1 { return \.colorHcpBackTees1 }
if backTees && option == 2 { return \.colorHcpBackTees2 }
if !backTees && option == 1 { return \.colorHcpFrontTees1 }
if !backTees && option == 2 { return \.colorHcpFrontTees2 }
fatalError("We were supposed to return a keyPath for choice")
}
func test() {
backTees = true
option = 2
print("Before: \(self.colorHcpBackTees2)")
// Now update the correct property using the choice KeyPath
self[keyPath: choice] = .Azul
print("After: \(self.colorHcpBackTees2)")
backTees = false
option = 1
// Assign it to another variable, just to show you can
let choiceFront1 = choice
option = 2
// choiceFront1 still refers to !backTees and option 1
// even though option and choice have changed
print("colorHcpFrontTees1 = \(self[keyPath: choiceFront1])")
colorHcpFrontTees1 = .Verde
print("colorHcpFrontTees1 = \(self[keyPath: choiceFront1])")
}
}
Run the test:
Foo().test()
Output:
Before: Blanca
After: Azul
colorHcpFrontTees1 = Roja
colorHcpFrontTees1 = Verde
Stopping reference variables changing the value of the original variable
The whole point of reference semantics (as used by classes) is that all variables point to the same (i.e., they reference the same) object in memory. If you don't want that behaviour, you should use value types (Struct, Enum, Array...) or create copies of your object.
If CustomClass
implements the NSCopying
protocol you can do:
var referenceVariable = originalVariable.copy()
If it doesn't, you'll have to find some other way to copy it or implement the protocol yourself.
Wrapping the class in a struct will just make two different structs each containing a different reference to the same object.
Assigning a reference from a class member to variable in Swift
why userDataStore doesn't point to profileInteractor.userDataStore !?
In this line:
var profileInteractor = ProfileInteractor(userDataStore: UserDataStore())
You created a new ProfileInteractor
object and a new UserDataStore
object. Then, you made profileInteractor
refer to the ProfileInteractor
object.
In the next line:
var userDataStore = profileInteractor.userDataStore
You are making userDataStore
refer to the same object as profileInteractor.userDataStore
. Now anything you do to the UserDataStore
object by using userDataStore
will be reflected on profileInteractor.userDataStore
because they are essentially the same thing.
However, this line changes everything:
profileInteractor.userDataStore = nil
You made profileInteractor.userDataStore
refer to nothing. This DOES NOT mean that the UserDataStore
object is destroyed. This just means that you no longer can use profileInteractor.userDataStore
to access the UserDataStore
object. But guess what is still referring to the UserDataStore
object? userDataStore
!
So the answer to your question is that userDataStore
did point to the same object as profileInteractor.userDataStore
, until you set profileInteractor.userDataStore
to nil.
What must I do, that userDataStore points to it?
Well, you already did. You just made profileInteractor.userDataStore
point to something else in the next line of code.
If you want a local variable to always point to the same thing that another local variable points to, your code can get quite messy, like in Ankit Thakur's answer, with unsafe pointers and stuff. If you are passing the variable to a method, you can use the inout
keyword.
Is Swift Pass By Value or Pass By Reference
Types of Things in Swift
The rule is:
Class instances are reference types (i.e. your reference to a class instance is effectively a pointer)
Functions are reference types
Everything else is a value type; "everything else" simply means instances of structs and instances of enums, because that's all there is in Swift. Arrays and strings are struct instances, for example. You can pass a reference to one of those things (as a function argument) by using
inout
and taking the address, as newacct has pointed out. But the type is itself a value type.
What Reference Types Mean For You
A reference type object is special in practice because:
Mere assignment or passing to function can yield multiple references to the same object
The object itself is mutable even if the reference to it is a constant (
let
, either explicit or implied).A mutation to the object affects that object as seen by all references to it.
Those can be dangers, so keep an eye out. On the other hand, passing a reference type is clearly efficient because only a pointer is copied and passed, which is trivial.
What Value Types Mean For You
Clearly, passing a value type is "safer", and let
means what it says: you can't mutate a struct instance or enum instance through a let
reference. On the other hand, that safety is achieved by making a separate copy of the value, isn't it? Doesn't that make passing a value type potentially expensive?
Well, yes and no. It isn't as bad as you might think. As Nate Cook has said, passing a value type does not necessarily imply copying, because let
(explicit or implied) guarantees immutability so there's no need to copy anything. And even passing into a var
reference doesn't mean that things will be copied, only that they can be if necessary (because there's a mutation). The docs specifically advise you not to get your knickers in a twist.
store reference in variable SWIFT 4
Don't do that.
Create a data model using a class
. A class is reference type
class Model {
var name : String
var email : String
init(name: String, email: String) {
self.name = name
self.email = email
}
}
Declare the data source array
var models = [Model]()
In the cell declare a property of the model (by the way class names start with a capital letter)
class CustomCell: TableViewCell {
@IBOutlet weak var textField: UITextField!
var model: Model! {
didSet {
textField.text = model.email
}
}
override func awakeFromNib() {
super.awakeFromNib()
textField.delegate = self
}
}
extension CustomCell: UITextFieldDelegate {
func textFieldDidEndEditing(_ textField: UITextField) {
model.email = textField.text ?? ""
}
}
In cellForRow pass the model to the cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as! CustomCell
cell.model = models[indexPath.row]
return cell
}
Due to the reference semantics the value in the model is preserved.
Related Topics
Swiftui Call Function on Variable Change
Parsing a Iso8601 String to Date in Swift
Sprite Kit Physicsbody.Resting Behavior
Does a Mutating Struct Function in Swift Create a New Copy of Self
Uitextfield Setting Maximum Character Length in Swift
Implementing a Drag-And-Drop Zone in Swift
Differencebetween Type Safety and Type Inference
How to Open Settings App Programmatically
How to Retrieve Alamofire Response Header for a Request
Difference Between Associated and Raw Values in Swift Enumerations
Swift 4 Decode Simple Root Level JSON Value
Parse.Com Querying User Class (Swift)
How to Validate Dynamically Added Textfields on a Button Click in Swiftui
Cannot Load Underlying Module for Xctest