What the difference when declaring these variables in swift using ! or () - ios

What is the difference of declaring variables this way?
var contacts: [Person]!
var contacts = [Person]()

By using var contacts: [Person]! you don't actually initialize a Person array.
var contacts: [Person]! // contacts still nil
var contacts = [Person]() // Person array with 0 objects
If you use () instead you initialize an empty Person array.

Variable declarations in Swift take the following form:
var name: Type = initialValue
That is, you declare a variable called name of some Type, and set it to an initialValue.
There are many shorthand forms though, so you will see various alternatives. The one you see the most often is leaving off the Type part. If you do, then the type of name is “inferred” from the initialValue.
This is what is happening with var contacts = [Person](). The type is an Array of Person. The () is calling the initializer (i.e. creating the array).
Alternatively, you can declare a variable, with a type, but not give it an initial value. But the compiler won’t let you use it until you are guaranteed to have set it with an initial value. So for example, you could write var contacts: [Person], then later contacts = [Person]().
When you write var contacts: [Person]!, with a !, you are declaring a variable of type Optional<[Person]> – that is, a type that can either be nil, or contain an array. Unlike regular arrays, optionals of arrays have a default value if you don’t initialize them. The default value is nil – that is, that the optional does not contain an array.
But the ! (instead of the more common ?) means it is declared to be a special kind of optional, called an “implicitly-unwrapped optional” – that is, an optional that, when you use it in certain ways, will act as if it isn’t optional. The big downside of this is that it will let you use it as if it isn’t an optional. But if you do and it is nil then your program will crash. So before anyone uses contacts, it will need to be initialized (such as with contacts = [Person]() or assigning some existing array to it)
For this reason, it’s best to not use these implicitly-unwrapped optionals except in very specific circumstances. They sometimes seem like they’re convenient but they’re usually not the best option as they’re dangerous.

The operator : is not declaring, its just saying which type a variable is
Operator = is as in every other language a declaring operator which in this case followed by the () which in this case declared a new array of Person.

Other people provided the differences, I'll give you the scenarios of when either should be used.
var contacts: [Person]! //implicitly unwrapped optional. #1
var contacts = [Person]() //array initialization. #2
I use #1 when I create a variable that won't be initialized by it's own class. This situation occurs when I implement a detail view that takes in information that is passed by another controller.
For #2, use when you want to initialized a new empty array.

Related

Swift optionals, unwrapping

I am learning the swift syntax and got a little confused with the optional type.
So, from the defination a swift type can not store the null value unless it is explicitly defined as an optional. So, what does the variable in the following line contains when it's declared.
var a:Int (declaring a variable without intializing it working fine in swift 3)
And also when we declare a variable as an optional with a "!",
var optionalSquare: Square! = Square(sideLength: 10, name: "Optional Square")
if we want to use the "optionalSquare" variable, we do not need to unwrap it cause we are sure(I think that is why we are using "!" instead of "?") it does not contain any null value. so why don't we declare it as a normal variable.
Please correct any false statements. Thank you.
what does [var a:Int] contains when it's declared
Nothing. Its value is undefined. Using it before assigning a value is a compilation error. You can declare it without initializing it, but you cannot use it.
This is part and parcel of Swift's philosophy of safety: in C, you could likewise leave a variable uninitialized, and its value would be undefined, but the compiler would not (by default) report error if you use it.
so why don't we declare it as a normal variable.
There's no reason that I can think of to make a local variable an implicitly unwrapped optional. The functionality is intended for properties ("ivars") on structs or classes. You should use them where it's impossible to set the property in the object's init, but it is certain that the value will be present before the object is used.
IBOutlets are probably the canonical use case. Another use that I find helpful is to allow setting a property by calling a method in init.
So, what does the variable in the following line contains when it's declared.
It does not matter, because you cannot access it anyway. A declaration like this tells Swift that you are going to decide on the value later. Reading the variable before assigning is an error that the compiler is going to catch.
why don't we declare [variables with forced unwrapping] it as a normal variables?
Because you may want to store nil in that variable at the times when it should not be used.
For example, you should make IB-assigned property implicitly unwrapped, because they need to be nil before NIB objects are "inflated", but after the init method has completed:
#IBOutlet private weak var myLabel: UILabel!
In order to make myLabel non-optional you would have to drop weak. On the other hand, you don't want to use exclamation point on each access of myLabel, because you know for sure that it must be initialized.
The same reasoning applies to other variables that you would like to make non-optional, but cannot assign in an initializer.
You can declare a non optional variable and not initialize it - the compiler doesn't complain as long as you do not use that variable. So this code
var num: Int
won't generate any error. However if you reference that variable before initializing, compilation fails
var num: Int
print(num)
In the former case there's no error because initialization can be deferred. You can declare a variable, and then initialize 100 lines after. As long as you don't reference it before initializing, you're ok.
To answer your second question, it's correct to say that in many cases it doesn't make much sense declaring and contextually initializing an implicitly unwrapped variable: a non optional variable is more appropriate.

Stored property initialisation for non optional

I am pretty new to swift .
I found the following document from Apple.
Classes and structures must set all of their stored properties to an
appropriate initial value by the time an instance of that class or
structure is created. Stored properties cannot be left in an
indeterminate state.
You can set an initial value for a stored property within an
initializer, or by assigning a default property value as part of the
property’s definition. These actions are described in the following
sections.
but the below piece of code noOfTyres is not initialised and the compiler doesn't complain ,please explain this .
class Vehicle
{
var noOfTyres: Int!
var engineCapacity: Int
init()
{
engineCapacity = 10
}
}
In your case, the compiler won't complain, until you try to use that value. Because you have the value un-wrapped (!) it assumes that it will never be nil and trying to access the value, will crash.
In this case I would add a default value to the property noOfTyres.
var noOfTyres: Int = 2
Or, you can add the value in the constructor to make sure that everytime an object gets created, the value must be set.
class Vehicle
{
var noOfTyres : Int!
var engineCapacity :Int
init(noOfTyres: Int)
{
self.noOfTyres = noOfTyres
engineCapacity=10;
}
}
Remember, if it's not optional, you are saying, the property will never be nil.
Another thing, by convention class names must be capitalized.
You can declare a stored property without assigning it an initial value if you make this property an optional. The property then either has a value or it is nil. An optional property is either declared with
var myOptional : Int?
or
var myOptional : Int!
And therefore noOfTyres is not initialized, while it is an optional and currently it is set to nil.
For more information, please, read the Apple documentation.
Additional information. The different types of optional declaration (! and ?) are explained in this post.
I am not sure ,if this can be the answer
The documentation says ,
Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter.
Hence its expected by the compiler as initialised ,definitely containing a value.But If we access it without a value during run time it will crash
If using an optional as a stored property ,it will have atlas a nil value & for other stored properties ,need an initialisation.

Should I use var or let for an object later mutated?

I have an iOS app that, upon startup, loads objects from persistent storage that will be manipulated later in the app. For example, on startup it loads patient profiles in an array. Does it matter if I define the items I add to the array as variables, versus constants, if they will be modified by the app later (say in a different View Controller)?
In my App Delegate, I load them like this:
func loadProfiles() {
var profileRecord: COpaquePointer = nil
if sqlite3_prepare_v2(db, "SELECT profilesid, objectSyncStatus, profileName, profileRelationship, profileFName, profileLName, profileAddress, profileCity, profileState, profileZip FROM profiles", -1, &profileRecord, nil) == SQLITE_OK {
if sqlite3_step(profileRecord) == SQLITE_ROW {
// Load profile stubs for each person
var newProfile = DBProfile(withDatabase: db, fromRecord: profileRecord, withLanguage: appLanguage, loadAllData: false)
patientProfiles.append(newProfile)
}
}
}
Of course, I get a warning that newProfile is not mutated, and it wants to change it to let newProfile = ... before it is added to the array. But, if I do that, will it become immutable later?
Thanks for the answers.
The compiler is actually really good at determining whether you should use let or var, and in this case, it is correct.
var should be used anywhere the data will be mutated. For example:
A struct value where the properties will be mutated
Pointers (like your COpaquePointer)
Instances of classes that will be reassigned to different class instances
let should be used anywhere the data will not be mutated. For example:
Constants
Values to be added to arrays, dictionaries, arguments to functions, etc.
Class instances where the instance will not be reassigned.
Note that for instances of classes, you can still modify the properties of the class even if it is defined as let. var should only be used in this case when the class itself will be reassigned.
In the case of your newProfile variable, during it's lifetime it is never mutated. The object is created, then immediately appended to your array. That array needs to be defined with var because it is mutated with that append, but newProfile never gets changed. You can change the value that was appended from newProfile through the array at a later date if you'd like because the patientProfiles array is mutable.
A good practice for when you are not sure whether to use let or var is to start with let and see if the compiler complains. If it does, then change it to var.
I see that you do not quite understand what is constant and how it works with value and reference types.
You can think of constant as glass box with lock and key.
Once you put something in box and lock it you threw away the key so you can see box contents (read properties and call non-mutating methods) but can not change it.
Words mutated and immutable can be only applied to value types because in case of value type the box holds value itself and if some method of value can change value then it must be marked with keyword mutating so it will not be visible through box glass.
In case of reference type the box holds reference to instance of type. If you define constant of reference type then you have box with reference. You can not change the reference, but you can read it and then go and find instance by that reference and do whatever you like with that instance.
In your case you define constant:
let newProfile = DBProfile(...)
and DBProfile is class (reference type).
You can not assign another reference to newProfile but you do whatever you like with object that referenced by newProfile. So you append it to patientProfiles array and you can get it later from this array and do what you want.

Swift Array Pass by Value...same memory address?

Can someone please clear this up for me.
I understand (thought) Swift passes arrays by value as it is a struct.
But when I pass an array via segue to the next view controller it appears to me that it is passing by reference, as when I check the memory address of the array they are the same.
This is how I'm checking
println("\(unsafeAddressOf(runs))") // 0x0000000174240c00
I would have thought these memory addresses would be different ? Or am I just confusing myself.
The Run / StaffTask classes both inherit from NSObject for saving purposes.
class Run: NSObject, NSCoding { }
Furthermore, if I access a item in the array
var service = self.staffTasks[indexPath.row]
and edit the value, both the service variable value and the element in the array are updated. They have the same memory address, as shown by
println("\(unsafeAddressOf(service)) \(unsafeAddressOf(self.staffTasks[indexPath.row]))")
Also...
staffTasks are a subset of a larger array called runs
When I search for the service object, with the larger set, I find that they are also the same memory address
if let index = find(self.runs, self.staff) {
println("local \(unsafeAddressOf(self.staff)) main list \(unsafeAddressOf(self.runs[index]))")
}
I am using NSCoding to save my objects, so I thought I would need to find the service object within the larger set, replace that object and then save them out.
But turns out I don't need to, I am able to edit the service variable and array of runs is updated on automatically ... like a reference type would be.
Passing? .. setting the Var
in prepare for segue, just setting the local var in the second VC using the standard way, var runsInSecondVC = runs. Not using, &pointers or any other weirdness.
Thanks for any help.
Class Basic Details
class Run: NSObject, NSCoding {
var runDate:NSDate!
var staffName:String!
var staffEmail:String!
var runTasks:[StaffTask]!
}
class StaffTask: NSObject, NSCoding {
var taskName:String
var taskTime:NSInteger
var clientName:String!
}
These are the basic of these classes. Nothing complicated.
passes arrays by value
No. Swift arrays are a value type. This does not mean they are pass-by-value. It means that you can mutate an array by way of a reference without affecting other references to which that array has been assigned.
You are getting a little confused about the array itself and the contents of the array.
..if I access a item in the array
var service = self.staffTasks[indexPath.row]
and edit the value, both the service variable value and the element in the array are updated. They have the same memory address...
Putting an object into an array doesn't copy the object. In fact, the array holds a reference to the object, so the line above actually says "make a variable, service that holds a reference to the object that self.staffTasks[indexPath.row] holds a reference to". There is only one object, now referred to in two places, so when you update the object that change is visible through both variables.

When to use ?, !, None, or Lazy?

I just started learning Swift and recently found out about
"Normal" variables (for lack of a better name):
ex: var test1: String
"Optional" variables
ex: var test2: String?
"Implicitly Unwrapped Optionals"
ex: var test3: String!
Lazy variables
ex: lazy var test4: String
My understanding is this:
Use "Optional" variables (?) when the variable may or may not be initialized at points in the future starting from initialization
Use "Implicitly Unwrapped Optionals" (!) when the variable is guaranteed to be initialized
Optionals can be converted to Implicitly Unwrapped Optionals via "Forced Unwrapping"
ex: let possibleString: String? = "Hello"
println(possibleString!)
Use "Lazy variables" when there is no need for something to be set until initialization (it seems these can be used with (?) or (!))
Therefore, my questions are:
When do I use option 1 - a variable without ? and without !
When do I use "lazy"
I read "lazy" is often used for singletons - why?
I have the most experience in Java and C++ terms, if that helps with my background for answering.
Edit: Here's everything I found (The main issue was "Normal" vs "Implicitly Unwrapped Optionals":
"Normal" variables must be initialized: (a) On the same line, (b) in the same scope before usage (Usage means some operation with the object), (c) by the end of the init iff the variable is a field. Note: The scope of init is everything in the scope of the class AND not in the scope of functions within the class.
Printing an Implicitly Unwrapped Optional will print "nil", but using the variable's functions will throw a runtime exception. Meanwhile, using (at all, including print) a Normal variable will not allow the program to compile at all
The purpose of using ! over "" (Nothing) is (a) More leniency since the program will compile (and run correctly given the variable is actually initialized) and (b) Lets you not initialize everything at the very beginning. Note: It is a compile time error to have any field undeclared if it is a Normal variable.
Not exactly that.
All variables must be initialised before the first use, and all class/struct stored properties must be assigned value in respective initialiser. Optionals are not about being allowed uninitalised at some point, but about being allowed to contain no value, which is represented by nil, which is still perfectly an initialised stated for such variable. Therefore, if something can not be known at the moment of initialisation then that's probably where you will use some sort of an optional (e.g. delegate for a view).
Implicitly unwrapped optionals is a sort of shorthand for cases when a variable might be empty, but we are absolutely sure that when we will be really using it it will hold an actual value (typical example is a property in a view controller that holds reference to a view).
Forced unwrapping does not convert optional into implicitly unwrapped optional, instead it gives you a value that is there if it's there (i.e. if optional is not nil), and throws an exception if it's not.
Lazy properties are used in cases when you want to defer their initialisation to a later stage, when the property is actually being used for first time. Usual case is if you need to access an expensive resource to do that (load huge file from disk, download it via network, etc), especially so if there might be cases when such property is not going to be used at all (why loading it from the disk if we will not use it probably?).
let's see Apple's example
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
}
Residence instances have a single Int property called numberOfRooms, with a default value of 1. Person instances have an optional residence property of type Residence?.
If you create a new Person instance, its residence property is default initialized to nil, by virtue of being optional.
1. If you need default value for property to be nil - use optional. Using variable without ? and ! - like 'numberOfRooms' -
You can set the initial value of a stored property from within an initializer, as shown above. Alternatively, specify a default property value as part of the property’s declaration. You specify a default property value by assigning an initial value to the property when it is defined.
NOTE
If a property always takes the same initial value, provide a default
value rather than setting a value within an initializer. The end
result is the same, but the default value ties the property’s
initialization more closely to its declaration. It makes for shorter,
clearer initializers and enables you to infer the type of the property
from its default value. The default value also makes it easier for you
to take advantage of default initializers and initializer inheritance.
2. ! is used to access the value wrapped inside variable when it is not nil, and throws exeption otherwise. So, you can use ! in order to make mark for users of you class - 'this value will not be nil at the time you unwrap it'
3. Lazy variable is used when you want to init it later, not at the time of whole object creation but exactly at the time you ask getter for data. this is useful when property stores an array, for example:
lazy var players: [String] = {
var temporaryPlayers = [String]()
temporaryPlayers.append("John Doe")
return temporaryPlayers
}()
When should I use lazy initialization?
One example of when to use lazy initialization is when the initial value for a property is not known until after the object is initialized.
Short explanation:
A non optional variable has always a value and can never be nil.
The variable must be initialized in the init method or in the declaration line.
var a : String
var b = "bar"
init {
a = "foo"
}
An implicit unwrapped optional variable must not be initialized in the init method
or in the declaration line but is guaranteed to have always a value when it's used
var a : String!
func viewDidLoad() {
a = "Hello"
a += " world!"
}
An optional variable may have a value and is nil at declaration
var a : String? // = nil
A lazy variable is initialized later at the moment it's used the first time
class foo {
lazy var bar : String = {
return "Hello"
}()
}

Resources