Cannot retrieve associated object [duplicate] - swift

The code below can be run in a Swift Playground:
import UIKit
func aaa(_ key: UnsafeRawPointer!, _ value: Any! = nil) {
print(key)
}
func bbb(_ key: UnsafeRawPointer!) {
print(key)
}
class A {
var key = "aaa"
}
let a = A()
aaa(&a.key)
bbb(&a.key)
Here's the result printed on my mac:
0x00007fff5dce9248
0x00007fff5dce9220
Why the results of two prints differs? What's more interesting, when I change the function signature of bbb to make it the same with aaa, the result of two prints are the same. And if I use a global var instead of a.key in these two function calls, the result of two prints are the same. Does anyone knows why this strange behavior happens?

Why the results of two prints differs?
Because for each function call, Swift is creating a temporary variable initialised to the value returned by a.key's getter. Each function is called with a pointer to their given temporary variable. Therefore the pointer values will likely not be the same – as they refer to different variables.
The reason why temporary variables are used here is because A is a non-final class, and can therefore have its getters and setters of key overridden by subclasses (which could well re-implement it as a computed property).
Therefore in an un-optimised build, the compiler cannot just pass the address of key directly to the function, but instead has to rely on calling the getter (although in an optimised build, this behaviour can change completely).
You'll note that if you mark key as final, you should now get consistent pointer values in both functions:
class A {
final var key = "aaa"
}
var a = A()
aaa(&a.key) // 0x0000000100a0abe0
bbb(&a.key) // 0x0000000100a0abe0
Because now the address of key can just be directly passed to the functions, bypassing its getter entirely.
It's worth noting however that, in general, you should not rely on this behaviour. The values of the pointers you get within the functions are a pure implementation detail and are not guaranteed to be stable. The compiler is free to call the functions however it wishes, only promising you that the pointers you get will be valid for the duration of the call, and will have pointees initialised to the expected values (and if mutable, any changes you make to the pointees will be seen by the caller).
The only exception to this rule is the passing of pointers to global and static stored variables. Swift does guarantee that the pointer values you get will be stable and unique for that particular variable. From the Swift team's blog post on Interacting with C Pointers (emphasis mine):
However, interaction with C pointers is inherently
unsafe compared to your other Swift code, so care must be taken. In
particular:
These conversions cannot safely be used if the callee
saves the pointer value for use after it returns. The pointer that
results from these conversions is only guaranteed to be valid for the
duration of a call. Even if you pass the same variable, array, or
string as multiple pointer arguments, you could receive a different
pointer each time. An exception to this is global or static stored
variables. You can safely use the address of a global variable as a
persistent unique pointer value, e.g.: as a KVO context parameter.
Therefore if you made key a static stored property of A or just a global stored variable, you are guaranteed to the get same pointer value in both function calls.
Changing the function signature
When I change the function signature of bbb to make it the same with aaa, the result of two prints are the same
This appears to be an optimisation thing, as I can only reproduce it in -O builds and playgrounds. In an un-optimised build, the addition or removal of an extra parameter has no effect.
(Although it's worth noting that you should not test Swift behaviour in playgrounds as they are not real Swift environments, and can exhibit different runtime behaviour to code compiled with swiftc)
The cause of this behaviour is merely a coincidence – the second temporary variable is able to reside at the same address as the first (after the first is deallocated). When you add an extra parameter to aaa, a new variable will be allocated 'between' them to hold the value of the parameter to pass, preventing them from sharing the same address.
The same address isn't observable in un-optimised builds due to the intermediate load of a in order to call the getter for the value of a.key. As an optimisation, the compiler is able to inline the value of a.key to the call-site if it has a property initialiser with a constant expression, removing the need for this intermediate load.
Therefore if you give a.key a non-determininstic value, e.g var key = arc4random(), then you should once again observe different pointer values, as the value of a.key can no longer be inlined.
But regardless of the cause, this is a perfect example of how the pointer values for variables (which are not global or static stored variables) are not to be relied on – as the value you get can completely change depending on factors such as optimisation level and parameter count.
inout & UnsafeMutable(Raw)Pointer
Regarding your comment:
But since withUnsafePointer(to:_:) always has the correct behavior I want (in fact it should, otherwise this function is of no use), and it also has an inout parameter. So I assume there are implementation difference between these functions with inout parameters.
The compiler treats an inout parameter in a slightly different way to an UnsafeRawPointer parameter. This is because you can mutate the value of an inout argument in the function call, but you cannot mutate the pointee of an UnsafeRawPointer.
In order to make any mutations to the value of the inout argument visible to the caller, the compiler generally has two options:
Make a temporary variable initialised to the value returned by the variable's getter. Call the function with a pointer to this variable, and once the function has returned, call the variable's setter with the (possibly mutated) value of the temporary variable.
If it's addressable, simply call the function with a direct pointer to the variable.
As said above, the compiler cannot use the second option for stored properties that aren't known to be final (but this can change with optimisation). However, always relying on the first option can be potentially expensive for large values, as they'll have to be copied. This is especially detrimental for value types with copy-on-write behaviour, as they depend on being unique in order to perform direct mutations to their underlying buffer – a temporary copy violates this.
To solve this problem, Swift implements a special accessor – called materializeForSet. This accessor allows the callee to either provide the caller with a direct pointer to the given variable if it's addressable, or otherwise will return a pointer to a temporary buffer containing a copy of the variable, which will need to be written back to the setter after it has been used.
The former is the behaviour you're seeing with inout – you're getting a direct pointer to a.key back from materializeForSet, therefore the pointer values you get in both function calls are the same.
However, materializeForSet is only used for function parameters that require write-back, which explains why it's not used for UnsafeRawPointer. If you make the function parameters of aaa and bbb take UnsafeMutable(Raw)Pointers (which do require write-back), you should observe the same pointer values again.
func aaa(_ key: UnsafeMutableRawPointer) {
print(key)
}
func bbb(_ key: UnsafeMutableRawPointer) {
print(key)
}
class A {
var key = "aaa"
}
var a = A()
// will use materializeForSet to get a direct pointer to a.key
aaa(&a.key) // 0x0000000100b00580
bbb(&a.key) // 0x0000000100b00580
But again, as said above, this behaviour is not to be relied upon for variables that are not global or static.

Related

How am I able to change this constant? [duplicate]

I'm really new to Swift and I just read that classes are passed by reference and arrays/strings etc. are copied.
Is the pass by reference the same way as in Objective-C or Java wherein you actually pass "a" reference or is it proper 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.
Everything in Swift is passed by "copy" by default, so when you pass a value-type you get a copy of the value, and when you pass a reference type you get a copy of the reference, with all that that implies. (That is, the copy of the reference still points to the same instance as the original reference.)
I use scare quotes around the "copy" above because Swift does a lot of optimization; wherever possible, it doesn't copy until there's a mutation or the possibility of mutation. Since parameters are immutable by default, this means that most of the time no copy actually happens.
It is always pass-by-value when the parameter is not inout.
It is always pass-by-reference if the parameter is inout. However, this is somewhat complicated by the fact you need to explicitly use the & operator on the argument when passing to an inout parameter, so it may not fit the traditional definition of pass-by-reference, where you pass the variable directly.
Here is a small code sample for passing by reference.
Avoid doing this, unless you have a strong reason to.
func ComputeSomeValues(_ value1: inout String, _ value2: inout Int){
value1 = "my great computation 1";
value2 = 123456;
}
Call it like this
var val1: String = "";
var val2: Int = -1;
ComputeSomeValues(&val1, &val2);
The Apple Swift Developer blog has a post called Value and Reference Types that provides a clear and detailed discussion on this very topic.
To quote:
Types in Swift fall into one of two categories: first, “value types”,
where each instance keeps a unique copy of its data, usually defined
as a struct, enum, or tuple. The second, “reference types”, where
instances share a single copy of the data, and the type is usually
defined as a class.
The Swift blog post continues to explain the differences with examples and suggests when you would use one over the other.
When you use inout with an infix operator such as += then the &address symbol can be ignored. I guess the compiler assumes pass by reference?
extension Dictionary {
static func += (left: inout Dictionary, right: Dictionary) {
for (key, value) in right {
left[key] = value
}
}
}
origDictionary += newDictionaryToAdd
And nicely this dictionary 'add' only does one write to the original reference too, so great for locking!
Classes and structures
One of the most important differences between structures and classes is that structures are always copied when they are passed around in your code, but classes are passed by reference.
Closures
If you assign a closure to a property of a class instance, and the closure captures that instance by referring to the instance or its members, you will create a strong reference cycle between the closure and the instance. Swift uses capture lists to break these strong reference cycles
ARC(Automatic Reference Counting)
Reference counting applies only to instances of classes. Structures and enumerations are value types, not reference types, and are not stored and passed by reference.
Classes are passed by references and others are passed by value in default.
You can pass by reference by using the inout keyword.
Swift assign, pass and return a value by reference for reference type and by copy for Value Type
[Value vs Reference type]
If compare with Java you can find matches:
Java Reference type(all objects)
Java primitive type(int, bool...) - Swift extends it using struct
struct is a value type so it's always passed as a value. let create struct
//STEP 1 CREATE PROPERTIES
struct Person{
var raw : String
var name: String
var age: Int
var profession: String
// STEP 2 CREATE FUNCTION
func personInformation(){
print("\(raw)")
print("name : \(name)")
print("age : \(age)")
print("profession : \(profession)")
}
}
//allow equal values
B = A then call the function
A.personInformation()
B.personInformation()
print(B.name)
it have the same result when we change the value of 'B' Only Changes Occured in B Because A Value of A is Copied, like
B.name = "Zainab"
a change occurs in B's name. it is Pass By Value
Pass By Reference
Classes Always Use Pass by reference in which only address of occupied memory is copied, when we change similarly as in struct change the value of B , Both A & B is changed because of reference is copied,.

Passing variables by reference in Swift

I started learning c++ and now I am wondering if I can do some things in Swift as well.
I never actually thought about what happens when we pass a variable as an argument to a function in Swift.
Let's use a variable of type string for examples.
In c++ I can pass an argument to a function either by making a copy of it, or by passing a reference/pointer.
void foo(string s) or void foo (string& s);
In the 1st case the copy of my original variable will be created, and foo will receive a copy. In the 2nd case, I basically pass an address of the variable in memory without creating a copy.
Now in Swift I know that I can declare an argument to a function to be inout, which means I can modify the original object.
1) func foo(s:String)...
2) func testPassingByReference(s: inout String)...
I made an extension to String to print the address of the object:
extension String {
func address() -> String {
return String(format: "%p", self);
}
}
The result was not that I expected to see.
var str = "Hello world"
print(str.address())
0x7fd6c9e04ef0
func testPassingByValue(s: String) {
print("he address of s is: \(s.address())")
}
func testPassingByReference(s: inout String) {
print("he address of s is: \(s.address())")
}
testPassingByValue(s: str)
0x7fd6c9e05270
testPassingByReference(s: &str)
0x7fd6c9e7caf0
I understand why the address is different when we pass an argument by value, but it's not what I expected to see when we pass an argument as an inout parameter.
Apple developer website says that
In Swift, Array, String, and Dictionary are all value types.
So the question is, is there any way to avoid copying objects that we pass to functions (I can have a pretty big array or a dictionary) or Swift doesn't allow us do such things?
Copying arrays and strings is cheap (almost free) as long as you don't modify it. Swift implements copy-on-write for these collections in the stdlib. This isn't a language-level feature; it's actually implemented explicitly for arrays and strings (and some other types). So you can have many copies of a large array that all share the same backing storage.
inout is not the same thing as "by reference." It is literally "in-out." The value is copied in at the start of the function, and then copied back to the original location at the end.
Swift's approach tends to be performant for common uses, but Swift doesn't make strong performance promises like C++ does. (That said, this allows Swift to be faster in some cases than C++ could be, because Swift isn't as restricted in its choice of data structures.) As a general rule, I find it very difficult to reason about the likely performance of arbitrary Swift code. It's easy to reason about the worst-case performance (just assume copies always happen), but it's hard to know for certain when a copy will be avoided.
Even though inout parameters modify the variable that was used as an input parameter to the function, they don't exactly work like by reference in other languages. The behaviour in Swift is called copy-in copy-out or call by value result. It means that when you use an inout parameter, at the time of the function call, its value is copied and inside the function, a local copy of the variable is modified. At the time of the functions return, it overwrites the value at the inout parameters original memory location with the modified copy value.
You are printing the address of the variable inside the function, hence you are actually printing the location of the copied value. Try printing after the function returned and you will see that you are printing the original location with the modified value.
For more information, see the In-Out parameters part of the documentation.

Why UnsafeRawPointer shows different result when function signatures differs in Swift?

The code below can be run in a Swift Playground:
import UIKit
func aaa(_ key: UnsafeRawPointer!, _ value: Any! = nil) {
print(key)
}
func bbb(_ key: UnsafeRawPointer!) {
print(key)
}
class A {
var key = "aaa"
}
let a = A()
aaa(&a.key)
bbb(&a.key)
Here's the result printed on my mac:
0x00007fff5dce9248
0x00007fff5dce9220
Why the results of two prints differs? What's more interesting, when I change the function signature of bbb to make it the same with aaa, the result of two prints are the same. And if I use a global var instead of a.key in these two function calls, the result of two prints are the same. Does anyone knows why this strange behavior happens?
Why the results of two prints differs?
Because for each function call, Swift is creating a temporary variable initialised to the value returned by a.key's getter. Each function is called with a pointer to their given temporary variable. Therefore the pointer values will likely not be the same – as they refer to different variables.
The reason why temporary variables are used here is because A is a non-final class, and can therefore have its getters and setters of key overridden by subclasses (which could well re-implement it as a computed property).
Therefore in an un-optimised build, the compiler cannot just pass the address of key directly to the function, but instead has to rely on calling the getter (although in an optimised build, this behaviour can change completely).
You'll note that if you mark key as final, you should now get consistent pointer values in both functions:
class A {
final var key = "aaa"
}
var a = A()
aaa(&a.key) // 0x0000000100a0abe0
bbb(&a.key) // 0x0000000100a0abe0
Because now the address of key can just be directly passed to the functions, bypassing its getter entirely.
It's worth noting however that, in general, you should not rely on this behaviour. The values of the pointers you get within the functions are a pure implementation detail and are not guaranteed to be stable. The compiler is free to call the functions however it wishes, only promising you that the pointers you get will be valid for the duration of the call, and will have pointees initialised to the expected values (and if mutable, any changes you make to the pointees will be seen by the caller).
The only exception to this rule is the passing of pointers to global and static stored variables. Swift does guarantee that the pointer values you get will be stable and unique for that particular variable. From the Swift team's blog post on Interacting with C Pointers (emphasis mine):
However, interaction with C pointers is inherently
unsafe compared to your other Swift code, so care must be taken. In
particular:
These conversions cannot safely be used if the callee
saves the pointer value for use after it returns. The pointer that
results from these conversions is only guaranteed to be valid for the
duration of a call. Even if you pass the same variable, array, or
string as multiple pointer arguments, you could receive a different
pointer each time. An exception to this is global or static stored
variables. You can safely use the address of a global variable as a
persistent unique pointer value, e.g.: as a KVO context parameter.
Therefore if you made key a static stored property of A or just a global stored variable, you are guaranteed to the get same pointer value in both function calls.
Changing the function signature
When I change the function signature of bbb to make it the same with aaa, the result of two prints are the same
This appears to be an optimisation thing, as I can only reproduce it in -O builds and playgrounds. In an un-optimised build, the addition or removal of an extra parameter has no effect.
(Although it's worth noting that you should not test Swift behaviour in playgrounds as they are not real Swift environments, and can exhibit different runtime behaviour to code compiled with swiftc)
The cause of this behaviour is merely a coincidence – the second temporary variable is able to reside at the same address as the first (after the first is deallocated). When you add an extra parameter to aaa, a new variable will be allocated 'between' them to hold the value of the parameter to pass, preventing them from sharing the same address.
The same address isn't observable in un-optimised builds due to the intermediate load of a in order to call the getter for the value of a.key. As an optimisation, the compiler is able to inline the value of a.key to the call-site if it has a property initialiser with a constant expression, removing the need for this intermediate load.
Therefore if you give a.key a non-determininstic value, e.g var key = arc4random(), then you should once again observe different pointer values, as the value of a.key can no longer be inlined.
But regardless of the cause, this is a perfect example of how the pointer values for variables (which are not global or static stored variables) are not to be relied on – as the value you get can completely change depending on factors such as optimisation level and parameter count.
inout & UnsafeMutable(Raw)Pointer
Regarding your comment:
But since withUnsafePointer(to:_:) always has the correct behavior I want (in fact it should, otherwise this function is of no use), and it also has an inout parameter. So I assume there are implementation difference between these functions with inout parameters.
The compiler treats an inout parameter in a slightly different way to an UnsafeRawPointer parameter. This is because you can mutate the value of an inout argument in the function call, but you cannot mutate the pointee of an UnsafeRawPointer.
In order to make any mutations to the value of the inout argument visible to the caller, the compiler generally has two options:
Make a temporary variable initialised to the value returned by the variable's getter. Call the function with a pointer to this variable, and once the function has returned, call the variable's setter with the (possibly mutated) value of the temporary variable.
If it's addressable, simply call the function with a direct pointer to the variable.
As said above, the compiler cannot use the second option for stored properties that aren't known to be final (but this can change with optimisation). However, always relying on the first option can be potentially expensive for large values, as they'll have to be copied. This is especially detrimental for value types with copy-on-write behaviour, as they depend on being unique in order to perform direct mutations to their underlying buffer – a temporary copy violates this.
To solve this problem, Swift implements a special accessor – called materializeForSet. This accessor allows the callee to either provide the caller with a direct pointer to the given variable if it's addressable, or otherwise will return a pointer to a temporary buffer containing a copy of the variable, which will need to be written back to the setter after it has been used.
The former is the behaviour you're seeing with inout – you're getting a direct pointer to a.key back from materializeForSet, therefore the pointer values you get in both function calls are the same.
However, materializeForSet is only used for function parameters that require write-back, which explains why it's not used for UnsafeRawPointer. If you make the function parameters of aaa and bbb take UnsafeMutable(Raw)Pointers (which do require write-back), you should observe the same pointer values again.
func aaa(_ key: UnsafeMutableRawPointer) {
print(key)
}
func bbb(_ key: UnsafeMutableRawPointer) {
print(key)
}
class A {
var key = "aaa"
}
var a = A()
// will use materializeForSet to get a direct pointer to a.key
aaa(&a.key) // 0x0000000100b00580
bbb(&a.key) // 0x0000000100b00580
But again, as said above, this behaviour is not to be relied upon for variables that are not global or static.

Where is my variable being stored? (Swift)

One of my little experiments with Swift:
func store<T>(var x: T) -> (getter: (Void -> T), setter: (T -> Void)) {
return ({ x }, { x = $0 })
}
x is a value type.
My questions are:
Where exactly is x being stored (in terms of stack/heap)?
What are the pitfalls of storing x like this?
Is this safe?
When is x going to be destroyed (if ever)?
Parameters are passed to functions and methods by value - that means that a copy of the parameter is created and used in the function body.
Parameters received by functions and methods are immutable, which means their value cannot be changed. However the var modifier makes a parameter mutable - what's important to keep into account is that the copy of the parameter is mutable: the parameter passed to the function has no relationship with the parameter received by the function body, besides the initial copy. That said, making a parameter mutable via the var modifier makes it changeable, but its lifetime ends with the function body and does not affect the original parameter passed to the function.
There's another option, the inout modifier, which works like the var, but when the function returns the value is copied back into the variable passed in.
It's worth mentioning that so far I have implicitly taken value types only into account. If an instance of a reference type (class or closure) is passed to the function, as a var parameter, any change made through that parameter is actually done to the instance passed to the function (that's the most significant difference between value and reference types). The instance pointed by the x variable has the same lifetime of the parameter passed to the function.
All that said, in your case it works in a slightly different way. You are returning a closure (ok, they are 2, but that doesn't change the conclusion), and the closure captures x, which causes x to be kept alive for as long as the variable the closure is assigned to is in scope:
let x = 5
let (getter, setter) = store(x)
In the above code, when getter and setter will be deallocated, x (as the variable defined in the store function) will cease to exist too.
To answer to your questions:
x is a variable created when the store function is invoked. Since you are explicitly mentioning value types, then x should be allocated on the stack (as opposed to the heap, which should be used for reference types)
the pitfall is that it's deallocated when the 2 return values (which are reference types, being closure reference types) are deallocated
it could be useful in some niche cases, but generally I would stay away from it - note that it's my own opinion
already described above (when the function returns values are deallocated)

Is Swift Pass By Value or Pass By Reference

I'm really new to Swift and I just read that classes are passed by reference and arrays/strings etc. are copied.
Is the pass by reference the same way as in Objective-C or Java wherein you actually pass "a" reference or is it proper 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.
Everything in Swift is passed by "copy" by default, so when you pass a value-type you get a copy of the value, and when you pass a reference type you get a copy of the reference, with all that that implies. (That is, the copy of the reference still points to the same instance as the original reference.)
I use scare quotes around the "copy" above because Swift does a lot of optimization; wherever possible, it doesn't copy until there's a mutation or the possibility of mutation. Since parameters are immutable by default, this means that most of the time no copy actually happens.
It is always pass-by-value when the parameter is not inout.
It is always pass-by-reference if the parameter is inout. However, this is somewhat complicated by the fact you need to explicitly use the & operator on the argument when passing to an inout parameter, so it may not fit the traditional definition of pass-by-reference, where you pass the variable directly.
Here is a small code sample for passing by reference.
Avoid doing this, unless you have a strong reason to.
func ComputeSomeValues(_ value1: inout String, _ value2: inout Int){
value1 = "my great computation 1";
value2 = 123456;
}
Call it like this
var val1: String = "";
var val2: Int = -1;
ComputeSomeValues(&val1, &val2);
The Apple Swift Developer blog has a post called Value and Reference Types that provides a clear and detailed discussion on this very topic.
To quote:
Types in Swift fall into one of two categories: first, “value types”,
where each instance keeps a unique copy of its data, usually defined
as a struct, enum, or tuple. The second, “reference types”, where
instances share a single copy of the data, and the type is usually
defined as a class.
The Swift blog post continues to explain the differences with examples and suggests when you would use one over the other.
When you use inout with an infix operator such as += then the &address symbol can be ignored. I guess the compiler assumes pass by reference?
extension Dictionary {
static func += (left: inout Dictionary, right: Dictionary) {
for (key, value) in right {
left[key] = value
}
}
}
origDictionary += newDictionaryToAdd
And nicely this dictionary 'add' only does one write to the original reference too, so great for locking!
Classes and structures
One of the most important differences between structures and classes is that structures are always copied when they are passed around in your code, but classes are passed by reference.
Closures
If you assign a closure to a property of a class instance, and the closure captures that instance by referring to the instance or its members, you will create a strong reference cycle between the closure and the instance. Swift uses capture lists to break these strong reference cycles
ARC(Automatic Reference Counting)
Reference counting applies only to instances of classes. Structures and enumerations are value types, not reference types, and are not stored and passed by reference.
Classes are passed by references and others are passed by value in default.
You can pass by reference by using the inout keyword.
Swift assign, pass and return a value by reference for reference type and by copy for Value Type
[Value vs Reference type]
If compare with Java you can find matches:
Java Reference type(all objects)
Java primitive type(int, bool...) - Swift extends it using struct
struct is a value type so it's always passed as a value. let create struct
//STEP 1 CREATE PROPERTIES
struct Person{
var raw : String
var name: String
var age: Int
var profession: String
// STEP 2 CREATE FUNCTION
func personInformation(){
print("\(raw)")
print("name : \(name)")
print("age : \(age)")
print("profession : \(profession)")
}
}
//allow equal values
B = A then call the function
A.personInformation()
B.personInformation()
print(B.name)
it have the same result when we change the value of 'B' Only Changes Occured in B Because A Value of A is Copied, like
B.name = "Zainab"
a change occurs in B's name. it is Pass By Value
Pass By Reference
Classes Always Use Pass by reference in which only address of occupied memory is copied, when we change similarly as in struct change the value of B , Both A & B is changed because of reference is copied,.