What should be used to create the instances of classes in Swift and why?
please explain the usage of let and var during the instances creation in Swift
below is the code :-
class ConstantTest{
let constant: String
init(constant: String) {
self.constant = constant
}
func printConstant() {
print(constant)
}
}
let constanttest = ConstantTest(constant: "Hello")
constanttest.printConstant()
var test = ConstantTest(constant: "Hie")
test.printConstant()
Use let if:
it is a constant (or in the case of reference types like class, if the reference cannot be replaced with another reference); and
you're able to set it during the initialization process.
But if you need to be able to change it at a later point, use var, such as true variables whose values are not constant (or in the case of reference types, if you need to replace it with another instance). But variables and properties whose values are not set during the initialization process, you have to use var. For example, lazy stored properties use var because their value is not set when the initialization process completes, but only when you first reference it. Another example includes view controllers' references to their outlets that are hooked up only when the view hierarchy is created at a later point.
Needless to say, computed properties use var, too.
But, if you can use let, you should do so, as it's easier to write safe code if you know what is a constant and what is a variable. In your example, you'd use let.
Note: In the case of reference types, like class types, let does not mean that that the object itself is necessarily immutable, merely that you cannot replace it with another instance. If you want to enjoy control over whether it's immutable or not, consider using a value type (e.g. a struct).
Let me see if I can make that final note more clear. Consider:
class Foo {
var value: String
init(value: String) {
self.value = value
}
}
Then the following is permitted:
let obj = Foo(value: "a")
obj.value = "b" // changing mutable property of reference type, Foo, is permitted
But the following is not:
let obj = Foo(value: "a")
obj = Foo(value: "b") // replacing `obj` with a new instance of `Foo`, is not
If you don't want to be able to change value property, you can define value to be immutable (or at least, not publicly mutable), e.g.:
class Foo {
let value: String // or `private(set) var value: String`
init(value: String) {
self.value = value
}
}
Or don't define Foo as class (a reference type) and instead define it to be a struct (a value type):
struct Foo {
var value: String
init(value: String) {
self.value = value
}
}
let obj = Foo(value: "a")
obj.value = "b" // this is not permitted, because Foo value-type, `obj`, was declared with `let`, making it immutable
Note, that final example, declaring Foo as a value type (a struct) does change it fairly fundamentally, e.g.
var obj1 = Foo(value: "a")
var obj2 = obj1 // this value is a copy of `obj1` not a reference to the same object that `obj1` pointed to
obj1.value = "b"
print("\(obj1.value)") // will print "b"
print("\(obj2.value)") // will print "a"
But value types, while it requires a slightly different mindset to use them, are incredibly useful for easily writing safe code. See WWDC 2015 Building Better Apps with Value Types in Swift.
There are varying reasons to use each. The simplest way to explain this is that let is for defining constants, while var is for defining variables. When using let the value cannot be changed. So in your application if you need a value that can be changed, use var. As well you might think of searching for your answer, as there are many duplicates of this question.
Source: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html
Related
I'm developing a class with a lot of functionality. Some functions need a lot of time, so I would store the result at creation for later access. But if this value is never needed, the calculation was wasted time.
In this case I would use a marker, if the value is already calculated. If yes, use the stored value. If not, it will calculate the value and store it in its static variable.
So I need the function itself, a marker and a variable for the saved result. Three items for every function!
Is there in Swift anything build in like "optional static functions"??
I would prefer to use
a = function()
for every call. The first call will calculate and save the result, all others will only take the precalculated result (like from a cache).
Lazy stored properties
In your comment below you describe that
But I don't meant global statically values, but for each instance. So
if you use foo1 and foo2, than foo2 needs to calculate its own
function for its own, because it only depends on values of foo2. It
can not rely on the globally calculated version which was done before
by foo1. So it is something like a "local static variable"
So it seems you may have a heavy computation for each instance of Foo, and you want to make certain that this computation is performed at most once, for each given instance of Foo. This demand is very close to the very definition of lazy (stored) properties in Swift: if a first call is made to get the value of a given lazy property, the property will be instantiated (e.g. by a call to some method, execution of a once-only executed closure, or simply by a given value/literal), and the value stored in the property. All subsequent calls to the lazy property will simply make use of the stored value (given you don't choose to mutate the property: lazy instance properties may not be immutables).
E.g., in practice:
class Foo {
lazy var bar: Int = self.reallyHeavyCalculation()
lazy var baz: Int = {
print("... heavy stuff")
return 2 * self.baq
}()
private func reallyHeavyCalculation() -> Int {
// ...
print("... other heavy stuff")
return 42
}
var bax: Int?
var baq: Int // instance value used in once-only computation
// of (lazy) property baz: at baz instantiation
init(baq: Int) { self.baq = baq }
}
let foo1 = Foo(baq: 50)
print("My first foo has never accessed his bar or baz")
foo1.bax = foo1.bar // at first call: compute 'bar' for this Foo instance
var baxBaz = foo1.bar // 'foo1.bar' already computed
print(foo1.baz) // at first call: compute 'baz' for this Foo instance
baxBaz = foo1.baz // 'foo1.baz' already computed
/* Prints:
My first foo has never accessed his bar or baz
... other heavy stuff
... heavy stuff
100 */
Static properties are always computed lazily
(When I initially read your question, I perceived your use case to be that of class/static properties, that are to be computed only once. I will leave this part of the answer as it is still relevant to the subject, and might be helpful to future readers)
Static properties are always computed lazily, meaning they will only be instantiated with a value given at least one call to them. After this instantiation, e.g. in case of a static immutable property, the once-only calculated value is readily available and stored in the static property.
We may read from the Language Guide - Properties:
Type Properties
...
Stored type properties are lazily initialized on their first access.
They are guaranteed to be initialized only once, even when accessed by
multiple threads simultaneously, and they do not need to be marked
with the lazy modifier.
...
Global and Local Variables
...
Global constants and variables are always computed lazily, in a
similar manner to Lazy Stored Properties. Unlike lazy stored
properties, global constants and variables do not need to be marked
with the lazy modifier.
We can verify this behavior with simple example:
class Foo {
static let foo: Int = reallyHeavyCalculation() // lazy
static let bar: Int = {
print("... heavy stuff")
return 99
}() // lazy
private static func reallyHeavyCalculation() -> Int {
// ...
print("... other heavy stuff")
return 42
}
var bax: Int? = nil
var baz = Foo.bar
}
print("I've never had a foo")
let foo1 = Foo()
// first initializion of instance member 'baz' by
// type member 'bar': compute bar
print("I have a foo")
foo1.bax = Foo.foo // at first call: compute 'Foo.foo'
let foo2 = Foo() // 'Foo.bar' already computed
print("I have another foo")
foo2.bax = Foo.foo // 'Foo'foo' already computed
/* Prints:
I've never had a foo
... heavy stuff
I have a foo
... other heavy stuff
I have another foo */
In the example above, the reallyHeavyComputation() (/closure associated with Foo.bar) method will be called exactly once in case you ask (at least once) for the value of the static immutable property Foo.foo (/Foo.bar). No additional calls will be made to reallyHeavyComputation() (/closure), even if you ask for the Foo.foo (/Foo.bar) value repeatedly.
I am overloading (or maybe implementing in this case) the += operator for a class (not a struct!). The operation modifies the state of the left-hand-side instance. I noticed that I can declare the left-hand-side element with let without any errors (and since it is an instance of a class, it's internal state changes with the operation). This of course is undesired, and should result in a compile-time-error. Is there a way to declare the overloaded operator as mutating to the left-hand-side element?
class MyClass {
static func +=(lhs: MyClass, rhs: MyClass) {
lhs.fu(rhs) // fu() changes internal state of lhs
}
}
let a = MyClass()
let b = MyClass()
a += b // this is legal but shouldn't be, since instance 'a' will
// have a different internal state after the concatenation
The let constant in this case is the reference a to the MyClass object that it points to. It prevents you from being able to do this:
let a = MyClass()
a = MyClass() //redefinition not allowed
It does not guarantee anything about the constancy of the members of that object however. Classes/objects exist to model constantly changing data, marking methods as mutating would be a bit tedious, because ultimately that's what they're supposed to do, in general.
You should be using structs in cases where you want controlled mutation.
In this article, it says (referencing the code below): "You must use lazy to prevent the closure for being created more than once."
private lazy var variable:SomeClass = {
let fVariable = SomeClass()
fVariable.value = 10
return fVariable
}()
Why would lazy prevent the closure from being created more than once? And why would the lack of lazy cause it to evaluate more than once?
The tutorial code you quote is this:
private lazy var variable:SomeClass = {
let fVariable = SomeClass()
fVariable.value = 10
return fVariable
}()
Contrast it with this:
private var variable:SomeClass {
let fVariable = SomeClass()
fVariable.value = 10
return fVariable
}
The first one initializes variable to a newly created SomeClass instance, once at most (and maybe not even that many times). The second one is a read-only computed variable and creates a new SomeClass instance every time its value is read.
Your intuition is right, that article is incorrect. I'm guessing the author is conflating/confusing computed property syntax with the immediately-executed-closure trick. The lazy keyword has nothing to do with how many times the closure is executed. lazy simply causes the property to remain uninitialized until first access, at which point the expression on the right hand side of the equal sign is evaluated.
To simplify, this:
var myVar: MyType {
return MyType()
}
is very different than this:
var myVar: MyType = MyType()
which is similar in storage but has different initialization semantics than this:
lazy var myVar: MyType = MyType()
In the first example, myVar is a computed property and the code inside of the curly braces is executed every time myVar is accessed. In other words, every time you access myVar you'd get a newly created object back.
In the second example, myVar is a stored property and the expression after the equal sign is evaluated once during initialization of the class or struct that contains that property.
In the third example, myVar is still a stored property but the evaluation of the expression after the equal sign (be it an initializer expression, a function invocation, or a closure invocation) is delayed until it's accessed.
As a side note, this line of code:
lazy var myVar: MyType = { ... }()
is equivalent to:
func doStuffAndReturnMyType() { ... }
lazy var myVar: MyType = doStuffAndReturnMyType()
The shorthand in the first example wasn't specifically designed for–it just works because Swift's type system (is awesome and) treats closures as unnamed (anonymous) functions.
I'm trying to store a type in a variable so that I can use it like a 1st class type later on.
class SomeModel {}
let someType = SomeModel.self
let array = Array<someType>()
In this case sure I could have done Array<SomeModel>() instead but I want to generalize it and let subclasses provide the value of someType.
However I get errors like someType isn't a type or use of undeclared type 'someType' on the last line.
If you need to store several type values in array, this works pretty well:
let array: [Any.Type] = [String.self, Int.self]
func someFunc<T>(model: T) -> Array<T> {
let array = Array<T>()
return array
}
let someType = SomeModel.self
let array = someFunc(someType())
Looks like this does what I want. The only drawback is that I have to create an instance of the desired type to pass. In this case its minimal overhead, but it just seems like a waste.
Another thing with using generics like this is it appears that the generic's possible types are computed at compile time, so at run time model.dynamicType doesn't necessarily match T. In most cases it will, but if you are doing any reflection driven stuff make sure to really check your use case well.
These days, this can be more easily and adaptably achieved by using .Type on a class or protocol. Note that only functions available to that root class or protocol will be accessible however, so you should ensure that a required initialiser of some kind is defined. For example:
protocol MyClass {
init(someValue: Int)
}
class MyWrapper {
let myClassType: MyClass.Type
init(classType: MyClass.Type) {
self.myClassType = classType
}
func new(with value: Int) -> MyClassType {
return MyClassType.init(someValue: value)
}
}
You can now initialise this rather silly factory class with a specific class implementing the MyClass protocol and when you call the new() function with an integer value it will generate a new instance of that class and return it.
In swift both the Array and Dictionary classes have different implementations depending on whether you declare them variable or constant. My question is can this type of functionality be used on classes you define, or is this reserved for Array, Dictionary?
The implementation of Array and Dictionary are not different for variables and constants -- instead, mutating methods (methods that change the value of any part of a struct) are only callable for variables (declared with var) but not callable for constants (declared with let).
That is to say:
struct MyType {
var name: String
func capitalizedName() -> String {
return name.capitalized()
}
mutating func setName(newName: String) {
self.name = newName
}
}
var myVariable = MyType(name: "Foo")
myVariable.setName("Bar")
println(myVariable.capitalizedName()) // print BAR
let myConstant = MyType(name: "Baz")
// not allowed by compiler:
// myConstant.setName("Nope!")