Accessing self from instance properties which are closures
This looks interesting, so I dig little deeper. Found that, you can access the class instance variables within the closure like self.instanceVariable
. Then the closure will capture the self
within it. So now the self
refers to the class instance itself. Your closure should be a lazy property.
A lazy property means that you can refer to self within the default closure, because the lazy property will not be accessed until after initialization has been completed and self is known to exist.
You are missing @lazy so that self
is unknown to the closure thats why it is printing it as (Function)
my guess.
class TableViewController: UIViewController {
var name = "anil"
// Since swift 2.0 came out @lazy is replaced by lazy
lazy var c1: () -> () = {
println(self)
println(self.name)
}
var c2: () -> () {
get {
return { println(self) }
}
}
var c3: () -> () {
return { println(self) }
}
override func viewDidLoad() {
super.viewDidLoad()
c1()
c2()
c3()
}
}
Output
<_TtC12TableViewApp19TableViewController: 0x10d54e000>
anil
<_TtC12TableViewApp19TableViewController: 0x10d54e000>
<_TtC12TableViewApp19TableViewController: 0x10d54e000>
Update
Assigning closure to a class instance variable results strong reference cycle. You should avoid this. Swift uses Capture list for that
If you assign a closure to a property of a class instance, and the closure captures that instance by referring to the instance or its members, you will create a strong reference cycle between the closure and the instance. Swift uses capture lists to break these strong reference cycles. For more information, see Strong Reference Cycles for Closures.
So the correct usage of closure could be
@lazy var c1: () -> () = {
[unowned self] in
println(self)
println(self.name)
}
Reference: Swift programming guide
Edit
@lazy has been changed to lazy
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.
Using self in instance closure variables
The problem is that you are using self
before the initialization of an instance of A
.
So there is not self
yet.
If you move the creation fo your closure inside the init
it will work
class A {
var value:Int = 3
var someFn : () -> () = { }
init() {
someFn = { print(self) }
}
}
A().someFn() // A
I needed to populate
someFn
with an empty value during the declaration, in order to be able to useself
inside theinit
. Infactself
cannot be used (inside theinit
) before all the properties without a default value have been initialized.
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
}
}
Accessing a closure property of an instance in RxSwift
Point 1 - Am I accessing a string property of a instance, right ?
Strictly speaking yes, but the instance will be created just for this access and then immediately destroyed. This is rather silly to do IMO.
Point 2ab - I think, I am accessing an instance after calling a closure,Actually what am I doing here?
Point 2a creates a Client value (not the same one used in Point 1, but it will have the same value.)
Point 2b calls setable()
on the value. The value object will be destroyed at the end of the viewDidLoad function.
Point 3 - Getting error, Cannot convert value of type '()' to closure result type 'Observable<ViewController.Client.DelegateEvent>'
The Client.live
computed property is a global, you are trying to access an instance variable of a particular ViewController
from inside that global, but there is no way to define which instance should be accessed.
So How can I fix this in a meaningful way ?
This question I cannot answer because I don't know what "fixed" means in this context...
How does self property refer to Instance object when using escaping closure ? (Swift 3)
Below in comments, you ask:
Inside of instance class,
self.x
equals instance propertyx
. Outside of instance class when we call closure, isself.x
still instance propertyx
?
Yes. The self
inside the closure refers to the object that created the closure, not to the object that ends up calling the closure (possibly much later). So if object A
passes a closure that refers to self.x
to another object, B
, when B
calls that closure, the self.x
still refer's to A
's x
property, not B
's.
In answer to the original question, yes, you can refer to whatever instance you want. It doesn't have to be self
.
The abstract way you phrase the question, though, makes me a bit suspicious. This question of "can I update any other instance" introduces some faint hints of code smell. The advantage of the closure pattern is that you're letting the object initiating some action to supply a closure that dictates what should happen in the first object when this other object finishes some task, keeping everything nicely, loosely coupled.
But when you start updating other unrelated objects, things start to feel a bit more tightly coupled, again. It all comes down to what this instance
is and what relationship it bears to the self
that created the closure.
But, in short, yes, you can update properties or call methods on items other than self
, but we'd need to better understand what those various objects were to comment on whether it's a good idea in this case or not.
Why cannot we use instance members in a closure definition?
The problem is that I'm trying to initialize a variable using an instance's variable while the instance itself has not been created yet.
So the problem is not related to closure nature. The same problem does exist in the following code where I'm trying to initialize nickname with name instance property.
class Person {
var name: String = "Amirreza"
var nickname: String = name
}
As compiler says, "property initializers run before 'self' is available", so in the above code the self.name is not available to initialize nickname and this is the source of the problem.
Here the solution is to use "lazy" keyword before nickname definition. The lazy keywork defers the initialization of the nickname property to when it is accessed for the first time. Means when we are sure that the instance has been created and name property is available.
To read more about lazy refer to https://docs.swift.org/swift-book/LanguageGuide/Properties.html
So the correct form of above code is:
class Person {
var name: String = "Amirreza"
lazy var nickname: String = name
}
And the correct form of the my main question code would be:
class Person {
var name: String = "Amirreza"
lazy var myClosure = { [weak self] (family: String) -> Void in
print(self!.name + " " + family)
}
func myFunc(family: String) -> Void {
print(self.name + " " + family)
}
}
Just note that we have to refer to properties inside closures with self explicitly like self.name. Meanwhile to avoid strong reference cycles we need to define a capture list in closure definition which in my example is [weak self].
By defining self as 'weak', self turns to an optional variable, so we have to unwrap it somehow which makes me to write self!.name in the closure.
Swift must use lazy for stored property when use self in closure?
When you are declaring label with lazy initial value is not calculated until the first time it is used.
so the probably the Instantiates views was completed.
But the concept of using let in Swift, variables which are let
have to be initialized before you can use self
.
Using lazy var
means that the compiler can verify that the value assigned to label won't be accessed before self is a valid object, because it won't be possible to call label until all other members of the class have been initialized.
Swift closures in autorelase pool accessing methods without self
Calling an instance method or referencing an instance property in a closure requires explicit self
if that closure is passed to a function taking an @escaping
parameter. That makes it explicit that the self
is possibly captured beyond the duration of the function call.
If the function parameter is not @escaping
then no explicit self
is required.
Here is a self-contained example:
func funcTakingNonescapingClosure(_ closure: () -> Void) { }
func funcTakingEscapingClosure(_ closure: @escaping () -> Void) { }
class Foo {
func anyMethod() { }
var myVariable = ""
func test() {
funcTakingNonescapingClosure {
anyMethod() // No error
print(myVariable) // No error
}
funcTakingEscapingClosure {
anyMethod()
// Call to method 'anyMethod' in closure requires explicit 'self.'
// to make capture semantics explicit
print(myVariable)
// Reference to property 'myVariable' in closure requires explicit
// 'self.' to make capture semantics explicit
}
}
}
In your example, Dispatch.main.async
takes an escaping closure, but autorelease
not.
Related Topics
How to Update Swift Dependencies in Xcode
Should Iboutlet Be Weak or Strong Var
One-Way Platform Collisions in Sprite Kit
Switch That Checks Nsindexpath's Row and Section
Difference Between Dispatchqueue Types in Swift
Using Cocoa Nssavepanel in Sandbox Causes Assertion Failure
How to Initialise Cvpixelbufferref in Swift
How to Check If Annotation Is Clustered (Mkmarkerannotationview and Cluster)
Swift: Assigning Function to Variable
Swift 2.0 Constraintswithvisualformat
Class Level or Struct Level Method in Swift Like Static Method in Java
Using Environmentobject in Watchos
Getting Timed Metadata in Swift iOS 8 from M3U8 Streaming Video
Local Swift Packages Stopped Working in Xcode 13
Uiimage Created from Mtkview Results in Color/Opacity Differences
iOS 10 App Crashes When Trying to Save Image to Photo Library
Add Links to Swift Classes in the Quick Help Documentation Comments
Guarantees About the Lifetime of a Reference in a Local Variable