Learning Swift at the moment and it is my first time learning to code as well. I am studying initializers at this point and I am stuck at the idea of custom initializers.
Looking at the code below, I am really not sure how this actually initializes the instances. Isn't setting the value of a property equal to an uninitialized instance just going to result in another un-initialized property?
init (region: String, population: Int, stopLights: Int) {
self.region = region
self.population = population
numberOfStoplights = stopLights
}
Any help is appreciated. Thanks!
init is invoked after memory for your object (struct or class instance) is allocated. At that time the object exists but its fields (member variables) contain unknown (undefined) values.
Swift, for safety and for type consistency, never allows access to undefined values. So you must assign a value to every field of your object in init, even if that is just some "default" value. Optional fields are initialized with nil.
Related
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,.
I am assigning the value of a custom class to another variable. Updating the value of the new variable is affecting the value of the original variable. However, I need to stop the reference variable from updating the original variable.
Here's a basic representation of what's happening:
var originalVariable = CustomClass()
originalVariable.myProperty = originalValue
var referenceVariable = originalVariable
referenceVariable.myProperty = updatedValue
print("\(originalVariable.myProperty)") //this prints the ->updatedValue<- and not the ->originalValue<-
I've tried wrapping the referenceVariable in a struct to make it a value type but it hasn't solved the problem.
I've found information regarding value and reference types but I haven't been able to find a solution.
My question in a nutshell: How do I stop an update to a reference variable from updating the original variable that it got its value assigned from?
Thanks in advance.
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.
As I started developing with Swift and searching through different tutorials and documentations about the language, I'm not sure about one thing.
You can declare an object / value with a specific data type like this:
var aString:String = "Test"
var anObject:SKScene = ASceneClass()
Or you can just do it like this:
var aString = "Test"
var anObject = ASceneClass()
The result will be exactly the same (ASceneClass inherits from SKScene of course)
As everyone is doing it different I wonder if there's a logical reason behind it or you do it for readability ?
Declaring type right after variable name is called Type Annotation
When you don't do that, you have to provide initial value
var aString = "Test"
Often value is not known at that moment, or you are not even sure if it's going to be not nil value, then you can declare it as optional
var aString:String?
If you would like to declare variable without any initiaization but you are sure it's not going to evaluate to nil, you force unwrap it
var aString:String!
This is the definition. In practice, it's always better to use type annotations even when you initialize variable with value, because later in your program you will notice anytime you mess something with the type of the variable.
Also, When you declare an array or dictionary, usually nested ones, Xcode might expect them to have type annotations since it might have some issues with writing values when the type is not known in advance.
To recap
You will want to use type annotations whenever you can, which means whenever you are sure about the variable's type in advance
Recommended/Documented way to declare a variable in swift is as follow:
var <variable name>: <type> = <initial value/expression>
Note: Given form declares a stored variable or stored variable property. Its used when you are clear about type annotation of it.
Though its valid to declare variable without its Type.
var variableName = <initial value>
Note: When you don't know type annotation its mandatory to assign 'Initial value' to that variable.
Refer Swift Documentation on Declaration for more details.
I'm new to Swift and is trying to learn the concept of Property. I saw the statements and code below from "swift programming language 2.1".
struct FixedLengthRange {
var firstvalue: Int
let length: Int
}
let rangeOfFourItems = FixedLengthRange(firstvalue: 0, length: 4)
rangeOfFourItems.firstvalue = 8 //error: cannot assign to property: rangeOfFourItems is a "let" constant
And the book provided the following explanation for the error:
This behavior is due to structures being value types. When an instance
of a value type is marked as a constant, so are all of its properties.
The same is not true for classes, which are reference types. If you
assign an instance of a reference type to a constant, you can still
change that instance’s variable properties.
Why is constant instance of a value type can NOT change its properties while constant instance of a reference type can? What is the reason behind it? The book did say how but failed to explain why. I think it is good practice to understand the reasons behind how things the way they are. Could someone please kindly explain it to me?
why is constant instance of a value type can NOT change its properties
Because value type is treated as an indivisible unit: it gets copied on assignment, passing it as a parameter behaves like a copy, and so using const-ness locks down the entire struct. In a sense, rangeOfFourItems variable represents the structure itself, not a pointer or a reference to it.
while constant instance of a reference type can?
This is not entirely correct to say that declaring a const variable of reference type makes the instance constant as well. Only the reference is constant, not the instance.
If you think about it, that is the only way this could be meaningfully implemented, because multiple variables can reference the same by-reference instance. If one of these variables is constant and the other one is not constant, assigning a non-const reference to a constant variable could not possibly lock down the referenced object, which would lock out the non-const reference as well:
var a = ByRefType()
let b = a; // b is a constant reference to the same instance as "a"
a.property = newValue; // Prohibiting this assignment would be inconsistent
Of course the constant variable itself (e.g. b above) could not be re-assigned, unlike the non-constant variable a.
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,.