Initializing Property via Closure

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:

Sample Image

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



Leave a reply



Submit