Why can i use self when I initialize property with a closure?
The target in your code is probably nil
, the reason that this might work is that:
...If you specify nil, UIKit searches the responder chain for an
object that responds to the specified action message and delivers the
message to that object
(from the documentation of the method)
You can verify that the target is actually nil
by setting a breakpoint during or after your controller's init and by inspecting the _targetActions
array (in the debugger's variables view) of the button (you can see that target
's address is 0x0
).
In your example, loginRegisterButton
is set during the controller's initialization which means that there is no self
yet (in other words you cannot guarantee that all instance variables are initialized at this point). The way lazy
solves this is that the actual assignment is deferred on first access.
Property Initialization with closures
This is not a retain cycle because self
is not what you think it is :)
Properties with initial value are "executed" even before any initializer runs, and for those properties self
points to a higher order function of this type:
(TestClass) -> () -> TestClass
So you don't really access the instance, but rather you access a static
-like method that does the initialization of all properties that have a default value. This is why you don't have a retain cycle.
addTarget
accepts an Any?
value for it's first argument, so this violates no type rules so the compiler doesn't complain that you don't pass a NSObject
instance there.
Checking the later behaviour - e.g. what happens if the button is added to the UI hierarchy and is tapped, reveals something interesting: the runtime sees that you passed a non-object as a target and sets null values for target and action:
Kotlin Property Initialization (Like swift using closures)
You can use apply()
:
val myLabel : UILabel().apply {
// in this block, `this` is the UILabel being initialized
color = "blue"
text = "hello"
}
Swift - `self` in variable initialization closure
It works in NSObject
subclasses because NSObject
(or rather NSObjectProtocol
) declares method self. That method is also available on metatypes (which are also NSObject
instances) and therefore you can call it in static context.
The fact that it actually works on UIButton
is probably a quirk of the compiler and the fact that UIButton
accepts Any?
as target.
Don't use it, it's not how it's intended to work.
See the bug SR-4559
Initialize closure in Swift
Simple example:
class TestClass {
var myClosure: (Int) -> ()
init(){
func myFunc(_:Int) {}
self.myClosure = myFunc
}
}
Or use an anonymous function:
class TestClass {
var myClosure: (Int) -> ()
init(){
self.myClosure = {_ in}
}
}
Or you could do the initialization as part if the declaration of myClosure
:
class TestClass {
var myClosure : (Int) -> () = {_ in}
init(){
}
}
But if you don't have the value of myClosure
at initialization time, why not make it an Optional?
class TestClass {
var myClosure: ((Int) -> ())?
init(){
}
}
Accessing self in initializing closure
This quoted example of the Migration Guide is misleading because it's related to a global variable.
The closure of a instance let
constant is called (once) immediately when the class is initialized. That's the reason why it cannot use other variables declared on the same level.
What you can do is to initialize initialize
(the variable name is not the best one ;-) ) lazily. The closure is also called only once but – as the guide describes – only the first time (when) it is used.
class SomeClass {
let other = SomeOtherClass()
lazy var initialize : () = {
let test = self.other
test.doSomething()
}()
func doSomething() {
// initialize will only be called once
_ = initialize
}
}
How can you initialize a struct with a closure parameter like this?
This works just like any function whose last parameter is a function. Trailing closure syntax is trailing closure syntax. The fact that the function is an initializer changes nothing.
So let me build up to it in stages. You know you can say:
func myfunc(whatever: () -> ()) {}
myfunc {}
Okay, but now let's make it a static method:
struct S {
static func myfunc(whatever: () -> ()) {}
}
S.myfunc {}
OK, but init
is a static method — it's just a static method whose name you are allowed to omit:
struct S {
let whatever: () -> ()
}
S {} // meaning S.init {}
self captured by a closure before all members were initialized - but I did initialize them
While I'm not entirely sure why Swift doesn't allow this (something to do with capturing self
to create the closure before the actual call to super.init
is made), I do at least know of a workaround for it. Capture a weak local variable instead, and after the call to super.init
set that local variable to self
:
class MyDataSource: UITableViewDiffableDataSource<String,String> {
var string : String?
init(string:String?) {
self.string = string
weak var selfWorkaround: MyDataSource?
super.init(tableView: UITableView()) { (_, _, _) -> UITableViewCell? in
print(selfWorkaround?.string)
return nil
}
selfWorkaround = self
}
}
The only problem with this, though, is that if the closure is executed during the call to super.init
, then selfWorkaround
would be nil inside the closure and you may get unexpected results. (In this case, though, I don't think it is - so you should be safe to do this.)
Edit: The reason we make the local variable weak
is to prevent the self
object from being leaked.
Related Topics
How to Create a Directory in Downloads Folder with Swift on MACos? Permission Exception
How to Use Bit Field with Swift to Store Values with More Than 1 Bit
Filteredarrayusingpredicate Does Not Exist in Swift Array
Swift: Cast Any Object to Int64 = Nil
Enum Not Working in Custom Initializer
Inferred to Have Type 'Anyclass', Which May Be Unexpected
Passing Data from Simple Nsview to Swiftui View
Swift 2, Protocol Extensions & Respondstoselector
Why Specify [Unowned Self] in Blocks Where You Depend on Self Being There
I Can't Include ' Symbol to Regular Expressions
Searchbar Problem While Trying to Search Firestore and Reload the Tableview
Stack Overflow When Defining Subscript on Ckrecord in Swift
Cursor Shifts to End on Edit of Formatted Decimal Textfield - Swift
Failed to Obtain a Cell from Its Datasource with Swift 3
Does the Initializer of an 'Open' Class Need to Be Open as Well