Compilation error when using lazy variable - ios

I am trying to understand how lazy works in swift. The following code compiles without any error.
import UIKit
class Test : UIViewController{
let i = 1
lazy var j:Int = self.i
}
Whereas if I remove the type of j and make it inferred like the code below,
import UIKit
class Test : UIViewController{
let i = 1
lazy var j = self.i
}
I get compilation error "Value of type 'NSObject -> () -> Test' has no member 'i'"
Can someone explain what is going on with the compiler. Thanks

You need to consider 3 aspects here.
A lazy stored property is a property whose initial value is not
calculated until the first time it is used. That is when you call
the property for the first time its value will be calculated.
As the actual value is created by evaluation, you need to declare
lazy variable's data type up front.
The properties you declare in your class are the instance variables,
if you need to access their values you need an instance(object) of
the class.
Let us consider following line from your non working code
lazy var j = self.i
Two problems are present in your non working code. First is you have not specified the data type of your lazy var. As the declaration is incomplete compiler won't treat 'j' as lazy var it will treat is as normal instance variable. You must be aware about swift's rule that whenever you declare any variable in the class you must assign some value to it or else you can make that variable optional. In above statement you are trying to assign i's value to j by using self within the class. When compiler is compiling that line no object of the class is created and the self you are using is nil that is why compiler is throwing the error(It will throw error even if you don't use self due to the same reason mentioned above).
Why it is not causing problems in your working code:
lazy var j:Int = self.i
As I have mentioned above the value to lazy var is assigned when you call that variable. How will you call that variable out side the class? Of course by creating object. And when you will call it with the help of object 'self' will point to the same object and self won't be nil it won't cause any problem.
In short two things you need to understand 3 things
While declaring lazy var you have to specify the data type
lazy var is not assigned when it is declared, it is assigned when it
is called
you can not call instance var without instance(object) of your class

Here is an example of lazy initialization with a view controller
Note the () at the end
lazy var myViewController : MyViewController? = {
let storyboard: UIStoryboard = UIStoryboard(name: "MyVC", bundle: nil)
return storyboard.instantiateViewController(withIdentifier: "MyAccount") as? MyViewController
}()

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

UIPanGestureRecognizer doesn't work without specified type [duplicate]

I have something that really puzzles me, specifically the following code triggers a compiler error "unresolved identifier self", and I am not sure why this is happening, as lazy means that at the time the property will be used, the class is already instantiated. Am I missing something?
Many thanks in advance.
Here is the code
class FirstClass {
unowned var second: SecondClass
init(second:SecondClass) {
self.second = second
print("First reporting for duty")
}
func aMethod() {
print("First's method reporting for duty")
}
}
class SecondClass {
lazy var first = FirstClass(second: self)
func aMethod() {
first.aMethod()
}
}
For some reason, a lazy property needs an explicit type annotation if its
initial value refers to self. This is mentioned on the swift-evolution mailing list, however I cannot explain why that is
necessary.
With
lazy var first: FirstClass = FirstClass(second: self)
// ^^^^^^^^^^^^
your code compiles and runs as expected.
Here is another example which demonstrates that the problem occurs
also with structs, i.e. it is unrelated to subclassing:
func foo(x: Int) -> Int { return x + 1 }
struct MyClass {
let x = 1
lazy var y = foo(0) // No compiler error
lazy var z1 = foo(self.x) // error: use of unresolved identifier 'self'
lazy var z2: Int = foo(self.x) // No compiler error
}
The initial value of y does not depend on self and does not need a
type annotation. The initial values of z1/z2 depend on self,
and it compiles only with an explicit type annotation.
Update: This has been fixed in Swift 4/Xcode 9 beta 3,
lazy property initializers can now reference instance members without explicit self, and without explicit type annotation. (Thanks to #hamish for the update.)

Access self in swift lazy var [duplicate]

I have something that really puzzles me, specifically the following code triggers a compiler error "unresolved identifier self", and I am not sure why this is happening, as lazy means that at the time the property will be used, the class is already instantiated. Am I missing something?
Many thanks in advance.
Here is the code
class FirstClass {
unowned var second: SecondClass
init(second:SecondClass) {
self.second = second
print("First reporting for duty")
}
func aMethod() {
print("First's method reporting for duty")
}
}
class SecondClass {
lazy var first = FirstClass(second: self)
func aMethod() {
first.aMethod()
}
}
For some reason, a lazy property needs an explicit type annotation if its
initial value refers to self. This is mentioned on the swift-evolution mailing list, however I cannot explain why that is
necessary.
With
lazy var first: FirstClass = FirstClass(second: self)
// ^^^^^^^^^^^^
your code compiles and runs as expected.
Here is another example which demonstrates that the problem occurs
also with structs, i.e. it is unrelated to subclassing:
func foo(x: Int) -> Int { return x + 1 }
struct MyClass {
let x = 1
lazy var y = foo(0) // No compiler error
lazy var z1 = foo(self.x) // error: use of unresolved identifier 'self'
lazy var z2: Int = foo(self.x) // No compiler error
}
The initial value of y does not depend on self and does not need a
type annotation. The initial values of z1/z2 depend on self,
and it compiles only with an explicit type annotation.
Update: This has been fixed in Swift 4/Xcode 9 beta 3,
lazy property initializers can now reference instance members without explicit self, and without explicit type annotation. (Thanks to #hamish for the update.)

Why latest Swift version always says variable is not initialized before use

Take an example
Class A {
var a : Int
override func viewDidLoad() {
super.viewDidLoad()
a=0
}
when it says variable is not initialized, even when i already declared in class first.
viewDidLoad is not the equivalent of init
I suggest you either use optionals:
var a:Int?
or you can initialize your variable directly in its declaration
var a:Int = 0
Last but not least, if you want to initialize any other way, do it in the init
override init() {
super.init()
a = 0
}
when you declare property in the class with Int it indicates it has no initializers. either give value at initialize time var a : Int = 0
or give value using init block which is use initialize the property of class. or you can also give declare as optional with ? var x : Int?
override init() {
super.init()
a = 0
}
Swift performs Two phase initialization :
Two-Phase Initialization
Class initialization in Swift is a two-phase
process. In the first phase, each stored property is assigned an
initial value by the class that introduced it. Once the initial state
for every stored property has been determined, the second phase
begins, and each class is given the opportunity to customize its
stored properties further before the new instance is considered ready
for use.”
Basically, this means that a property is not ready for use till it is provided an initial value.
In Objective-C, this was handled internally as the properties were set nil or 0 (depending on the data type) until initialized.
This behavior is provided by Optionals in Swift.
“You use optionals in situations where a value may be absent. An
optional says:
There is a value, and it equals x or
There isn’t a value at all”
As mentioned by other answers, you can declare an optional using a "?"
eg: var a : Int?
For details refer : The Swift Programming Language (Swift 2.2).

How to set up cross-referencing between UIViews in Swift

First q here, so trying to get protocol right...what I've done works, in that the data and views display correctly, but memory is not deallocating (still getting used to ARC after many years of allocating/deallocating), and I'm trying to figure out the right strategy. Document based app. When doc is created, view controller is instantiated, which creates several views which need to refer to each other for size/position/methods, and all of which need access to the doc data.
class MyDoc: UIDocument {
var data: Int
etc...
}
class MyController: UIViewController {
var doc: myDoc! // code which creates MyDoc instance assigns self to this property
var thisView1: MyView1!
var thisView2: MyView2!
thisView1 = MyView1(...)
thisView2 = MyView2(...)
thisView1.theOtherView2 = thisView2
thisView2.theOtherView1 = thisView1
thisView1.doc = self.doc
thisView2.doc = self.doc
}
class MyView1: UIView {
var theOtherView2: MyView2!
var doc: MyDoc!
}
class MyView2: UIView {
var theOtherView1: MyView1!
var doc: MyDoc!
}
I don't think I excluded anything meaningful. Assigning thisView1 and thisView2 to each other creates a strong reference cycle, right? I tried combining an unowned property on one with implicitly unwrapped on the other, per The Swift Programming Language, but kept having trouble with the init() methods of the views. Is using weak references and then unwrapping the optional all the time (though I make sure there's a valid value before proceeding from viewController) the only thing that'll work? I've read so many explanations that each new one now confuses me more.
Thank you!

Resources