Below code gives an error:
class HomeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let tableView = {
let t = UITableView(frame: .zero, style: .grouped)
t.dataSource = self
t.delegate = self
return t
}()
...
}
Error is:
Cannot assign value of type '(HomeViewController) -> () -> HomeViewController' to type '(any UITableViewDataSource)?'
However, if I change it to lazy var tableView = {}()
, then error goes away:
class HomeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
lazy var tableView = {
let t = UITableView(frame: .zero, style: .grouped)
t.dataSource = self
t.delegate = self
return t
}()
...
}
Why does lazy var
solve this error?
self
cannot be used in property initialisers because they are run before self
is fully initialised. The error message produced by this code makes it clear:
class Foo {
let x = 1
let y = x + 1 // Cannot use instance member 'x' within property initializer; property initializers run before 'self' is available
}
On the other hand, the initialisers of lazy var
s are guaranteed to be run after self
has been fully initialised, so you can use self
there.
With self
being unavailable, the token self
resolves to the NSObject
method named self
. This is an instance method that takes no arguments and returns Self
, so normally it would be of type () -> HomeViewController
. But in this case, there is no instance to call this instance method on, and you end up accessing the curried form. This is of type (HomeViewController) -> () -> HomeViewController
- i.e. a method that takes an instance of HomeViewController
, and returns a function that does what the self
method would do.
// f is of type (HomeViewController) -> () -> HomeViewController
let f = HomeViewController.`self`
// another example:
// g is of type (String) -> () -> String
let g = String.lowercased
g("ABC") // this expression is of type () -> String
g("ABC")() // this is of type String, and evaluates to "abc"