How is 'let' implemented? - ios

I pulled this example straight from this Apple page
struct FixedLengthRange {
var firstValue: Int
let length: Int
}
and if you assign an instance of this structure to a constant,
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
it says we can't change its property values even if it is declared as 'var'
This makes me wonder how let is implemented? I hope any assignments to it can be detected at compile time and show compile error. But in the above case, why does it apply to every property of the structure, regardless of how it is defined?
I tried to search for this, finding it very difficult to search with keyword 'let' as it is quite common term.
Can anyone help me to understand this?

It's because a struct is a value type. This means it cannot be mutated in place.
Thus, if we have a variable rangeOfFourItems that is a FixedLengthRange struct instance, and we want to set rangeOfFourItems.firstValue, we are actually ripping the struct instance right out of the rangeOfFourItems storage and replacing it with another struct instance with a different firstValue.
To see that this is true, declare rangeOfFourItems with var and attach a setter observer to it, and then change rangeOfFourItems.firstValue:
struct FixedLengthRange {
var firstValue: Int
let length: Int
}
var rangeOfFourItems = FixedLengthRange(firstValue:1, length:4) {
didSet {
print("Hey, you set me!")
}
}
rangeOfFourItems.firstValue = 2 // Hey, you set me!
This shows that merely setting the property of this struct instance actually sets the struct variable itself.
But in your code, we cannot do that, because rangeOfFourItems prevents this implicit assignment - it is declared with let, meaning it must remain a constant. Thus, setting rangeOfFourItems.firstValue is prevented at compiler level.
(If FixedLengthRange were a class instead of a struct, it would be a reference type, and would be mutable in place, and setting rangeOfFourItems.firstValue would be legal even if rangeOfFourItems was declared with let.)

Related

Difference between property and class instance swift

I am new to swift programming, and i have a question as follows:
I have a class named Weather
class Weather {
}
then i define 2 things:
var currentWeather1 = Weather()
var currentWeather2: Weather!
Are they different syntax or the same meaning? What are they actually created in memory with these 2 statements?
var currentWeather1 = Weather()
This declares a variable of type Weather and assigns a new instance of Weather to it. The syntax Weather() creates an instance and runs its initialiser. The compiler infers the type of currentWeather1 to be Weather. The statement above is exactly equivalent to
var currentWeather1: Weather = Weather()
The other statement:
var currentWeather2: Weather!
declares an implicit optional variable. This variable is of optional type i.e. it's type is Optional<Weather>. This means that it needs to be unwrapped if you want to get at the value. However, the ! means that the compiler will put in the unwrapping code for you. A normal optional would look like this:
var currentWeather3: Weather?
but when you need to use it, you have to unwrap it e.g.
if let foo = currentWeather3
{
// foo is the unwrapped weather
}
let string = currentWeather3?.description // string is an optional String
let string2 = currentWeather3!.description // string2 is a String
The last example with the ! is a forced unwrapping. If currentWeather3 is nil, when the line executes, the program will crash. The declaration of currentWeather2 means the compiler treats every mention of currentWeather2 as if it has an implicit ! after it.
The simple answer is
var currentWeather2: Weather!
Declares a variable by creating a references of the Weather in system table. But does not allocate any memory for the variable
var currentWeather1 = Weather()
Weather object is created by allocating memory and the location of the variable is assigned to the system table entry of age.
var currentWeather2: Weather!
The above statement does not allocate memory for an instance of Weather, it only allocates a stack variable currentWeather2. The reference pointers only are allocated on stack. The time it hits the currentWeather2 = Weather(), it allocates on "heap".
To access class properties & methods refer directly from the class name rather than with an instance of the class.
it will be helpful to understand more,it's in C# but concept is same
https://www.codeproject.com/Articles/76153/Six-important-NET-concepts-Stack-heap-value-types

What is the difference between a property and a variable in Swift?

From a few initial tutorials, I see that properties belong to a Class and are essentially 'global variables' as used in the C++ world (coded in this years ago). I also see variables as more of a 'local' entities only used / storing information within a method.
Then I came across this Quora thread: https://www.quora.com/Apple-Swift-programming-language/What-is-the-difference-between-a-property-and-a-variable
Now I see properties being able to execute code associated with their invocation. This is very cool, but also opened up a whole bunch of other questions for me.
Are there other simple and clear ways to remember the distinction between a property and a variable?
Properties belong to an object, whereas variables do not. A variable can be declared without having to be associated with a particular class, or other object. A property must be associated with a particular object (i.e.: a class, enum, or struct)
Local variables are just things that you work with. You have full control over these, and if you change a variable in a function, nothing outside of your function is ever gonna know. If I write a framework and you use it, and I decide to change something about a function's local variables, your app that uses my framework will keep working just as if nothing changed.
Classes, on the other hand, describe a contract. When you use a class, you have access to everything they publicly advertise. This means that if I write a framework and you use it, if I ever change or remove a public member on a class, your code will break if you were previously using that member.
For this reason, in many languages, it's bad practice to mark instance variables as public. Instance variables having no logic attached, if I want at some point to trigger something when a field is changed or if I want to remove the field entirely (and instead report a value in a sub-object or something), then I'm stuck with changing the public contract (turning the field in a pair of get/set methods, for instance), and possibly breaking your code.
Swift makes properties an indirection for this reason. Swift properties can be treated as dumb values for the most part, but if you ever need to change from a stored value to a computed value or something, you can do it without changing your class's interface. That way, you don't break existing code that relies on the property.
Swift variable, constant, Property
[Swift types]
variable - named storage of address. Every variable has a type which defines a memory size, attributes and behaviours
Swift variable and constants
constant is a variable but can not be modified after definition.
//definition
var <name> = <initial_value>
//type annotation
var <name>: <Swift_type> [= <initial_value>] // [] is optional
//var - variable
var myVariable1 = 11
var myVariable2: Int
myVariable2 = 12
//let - constant
let myConstant1 = 21
let myConstant2: Int
myConstant2 = 22
Global and local variable
Global variable is a variable which is defined out of function, class.
Local variable is: variable inside a type context(class, struct, enum)[About], inside a function, function parameter
Property
property - associate value with a type context. It is a variable + bounded getter/setter. It has field syntax but uses methods(getter/setter) under the hood.
Stored properties and computed properties
They can belong to instance(instance property) or type(type property):
Stored property (class, structure)
Computed property (class, structure, enum)
Stored property - is a local variable -> variable inside a type context. Swift stored property does not support instance variable like Objective-C.
variable stored properties - var
constant stored properties - let
It supports property observers (willSet, didSet)
Computed property - provide getter and optional setter to calculate a value every time
public class Person {
var firstName = "John"
var lastName = "Wick"
var fullNameComputedProperty: String {
get {
return "\(firstName) \(lastName)"
}
//optional
set {
let arr = newValue.split(separator: " ")
firstName = String(arr[0])
lastName = String(arr[1])
}
}
var addressStoredProperty: String {
//Property Observers
willSet {
print("old address:\(addressStoredProperty)")
print("new address:\(newValue)")
//addressStoredProperty is not updated yet
}
didSet {
print("old address:\(oldValue)")
print("new address:\(addressStoredProperty)")
}
}
}
Lazy Stored property
Property is calculate during first access to it(on demand)
only var lazy because let must have a value during initialization
Init/customize stored property by closure
Official doc
You are able to init/setup/customise a stored property with a help of closure
() at the end executes the closure immediately and assign a value to stored property(calculate and return a value).
in initializing case it is not possible to access to any instance variable or function because it has not initialized yet
in initializing case it will be executed only once for every object or if you use static - once for the class[Example]
Examples
func testStoredPropertyWithClosure() {
class ClassA { }
class ClassB {
static let staticStoredProperty: ClassA = {
//is called only when you access to it like ClassB.staticStoredProperty
print("init staticStoredProperty")
return ClassA()
}()
var storedProperty: ClassA = {
print("init storedProperty")
//self.foo() //Error: Class declaration cannot close over value 'self' defined in outer scope
return ClassA()
}()
func foo () {
storedProperty = {
print("customize storedProperty")
return ClassA()
}()
}
}
let b = ClassB()
b.foo()
ClassB.staticStoredProperty
}
closure stored property vs Computed property
closure stored property is called once and can be changed after initialization(if it is var)
Computed property is calculated every time when it is called
[Java variable, property...]

initializing class properties before use in Swift/iOS

I'm having trouble grasping the proper way of instantiating variables that always need to be set before an object is fully functional but may need to be instantiated after the constructor. Based on Swift's other conventions and restrictions it seems like there is a design pattern I'm unaware of.
Here is my use case:
I have a class that inherits from UIViewController and will programmatically create views based on user actions
I need to attach these views to this class, but to do so I need to retrieve their content based on configuration data supplied by another controller
I don't care if this configuration data is passed to the constructor (in which case it would always be required) or supplied by a secondary call to this object before it is used
My problem seems to be that both of the approaches in bullet 3 seem flawed.
In the first case, there is only one legitimate constructor this class can be called with, yet I'm forced to override other constructors and initialize member variables with fake values even if the other constructors are never intended to be used (I'm also trying to keep these variables as let types based on Swift's best practices).
In the second case, I'm effectively splitting my constructor into two parts and introduce an additional point of failure in case the second part fails to be called prior to class being used. I also can't move this second part to a method that's guaranteed to be called prior to usage (such as viewDidLoad) because I still need to pass in additional arguments from the config. While I can make sure to call the initPartTwo manually, I'd prefer to have a mechanism that better groups it with the actual constructor. I can't be the first one to run into this and it seems like there is a pattern I'm not seeing to make this cleaner.
UPDATE:
I ended up going with a modified version of the pattern matt suggested:
struct Thing {
let item1: String
let item2: String
struct Config {
let item3: String
let item4: String
}
var config:Config! {
willSet {
if self.config != nil {
fatalError("tried to initialize config twice")
}
}
}
init() {
self.item1 = ...
self.item2 = ...
...
}
public func phaseTwoInit(item3: String, item4: String) {
self.item3 = item3
self.item4 = item4
...
}
}
var t = Thing()
...
t.phaseTwoInit(...)
...
// start using t
If an initial instance variable property value can't be supplied at object initialization time, the usual thing is to declare it as an Optional. That way it doesn't need to be initialized by the class's initializers (it has a value - it is nil automatically), plus your code subsequently can distinguished uninitialized (nil) from initialized (not nil).
If the Optional if an implicitly unwrapped Optional, this arrangement need have no particular effect on your code (i.e. it won't have to be peppered with unwrappings).
If your objection is that you are forced to open the door to multiple settings of this instance variable because now it must be declared with var, then close the door with a setter observer:
struct Thing {
var name:String! {
willSet {
if self.name != nil {
fatalError("tried to set name twice")
}
}
}
}
var t = Thing()
t.name = "Matt" // no problem
t.name = "Rumplestiltskin" // crash

Xcode6 autogetters and autosetters

Xcode6 ios swift
I have created my own class and trying to make an autogetter and autosetter, but i don't really know if it's allowed.
var Birthday:NSDate {
get {return birthday}
set(newValue){birthday = newValue}
}
var BirthYear:Int32 {
get {}
set {}
}
The last part of code triggers error, missing return, so my question is that - Is there any possibility to make getter and setter without making a second variable
Stored properties in swift are backed by hidden instance variables - the property itself is its own getter and setter, unless you implement it as a computed property, in that case you have to provide your own getter and/or setter. So when you write:
var birthday: NSDate
you use it as:
let value = classInstance.birthday
to read its value, and
classInstance.birthday = someDate
to assign a new value. You don't have to do anything special to make that work.
Suggested reading: Properties
Side note: by convention variables and property should use lower camel case notation, so they should start with lowercase, and if made up of multiple words, make the first letter of each word in uppercase. For instance:
var single: Int
var multipleWordsVariable: String

Struct value types in Swift

I understand the difference between 'Value Types' and 'Reference Types'. I know 'Structures' are 'Value Types' and according to the Swift documentation all the values stored by the structure are themselves value types. Now my question is what if I have a stored property in a Struct that is an instance of a class. In that case, would the whole class would be copied or just its address?
Any help would be appreciated.
It copies the pointer to the instance. I just tested this in a playground.
struct MyStruct {
var instance: MyClass
}
class MyClass {
var name: String
init(name: String) {
self.name = name
println("inited \( self.name )") // Prints "inited Alex" only once
}
}
var foo = MyClass(name: "Alex") // make just one instance
var a = MyStruct(instance: foo) // make a struct that contains that instance
var b = a // copy the struct that references the instance
foo.name = "Wayne" // Update the instance
// Check to see if instance was updated everywhere.
a.instance.name // Wayne
b.instance.name // Wayne
What is different though, is that it's now two different references to the same object. So if you change one struct to a different instance, you are only hanging it for that struct.
b.instance = MyClass(name: "Vik")
// a and b no longer reference the same instance
a.instance.name // Wayne
b.instance.name // Vik
The playground is a great way to test out questions like these. I did not know the answer definitively when I read this question. But now I do :)
So don't be afraid to go play.
I think you misread the documentation. According to the The Swift Programming Language,
All structures and enumerations are value types in Swift. This means that any structure and enumeration instances you create—and any value types they have as properties—are always copied when they are passed around in your code.
Since classes are reference types, not value types, they are not copied even if they are properties of a value type, so only the address is copied.

Resources