Self. in Trailing Swift Closures, Meaning and Purpose

self. in trailing swift closures, meaning and purpose?

Does it have some profound meaning, and will I magically understand closures if I understand this?

No and no. Or perhaps, maybe and maybe.

The reason for this syntactical demand is that this might really be a closure, that is, it might capture and preserve its referenced environment (because the anonymous function you are passing might be stored somewhere for a while). That means that if you refer here to some property of self, such as myProperty, you are in fact capturing a reference to self. Swift demands that you acknowledge this fact explicitly (by saying self.myProperty, not merely myProperty) so that you understand that this is what's happening.

Why do you need to understand it? Because under some circumstances you can end up with a retain cycle, or in some other way preserving the life of self in ways that you didn't expect. This is a way of getting you to think about that fact.

(If it is known that this particular function will not act as a closure, i.e. that it will be executed immediately, then there is no such danger and Swift will not demand that you say self explicitly.)

Why do we need a weakSelf for functions/methods within closures?

credit to iOS nerds I know from a meetup

tl;dr you need to use self for instance methods, but don't need it for class methods. A class may have many instances, but it can only have one declaration of itself (which also contains its type/class/static functions).

Why error occurs 1: Bare in mind the alertFunc could have had a reference to a property.

It could have been :

private func logAction () {

print("someProperty = \(self.someProperty)")

}

So, in this case it's obvious that you are eventually referencing a property.


Why error occurs 2: Even if you don't have a reference to self within your function, still because you wrote it as an instance method, the self is implicitly passed on. But, we don't see!

An instance method is really just syntactic sugar for a function that takes an instance for the first parameter, which is self passed automatically.

Under the hood it may look something like this :

private func alertFunc (_ instance: MyType) {

print("someProperty = \(instance.someProperty)")

}

// and actually the call to it *may* look something like this:

MyType.someFunc(self)

We never see the self being passed! It's a syntactic sugar that deceives us.

So, if your method does not use self internally (i.e. doesn't rely on the state of the instance in any way) then it's actually probably best to make it a static/type/class method or free function.


Alternative1: use a free function.

class someClass {

...

}

func freeFunc {
print("Hi this is a free function, written outside the scope of any class...")
}

And then within your closure you call it using freeFunc()

Alternative2: Use a class function.

class someClass {

...

class private func alertFunc() {
print("Hi this was a class function, see the class at the beginning of the func definition")
}
}

And then within your closure you call it using yourClassName.alertFunc()


But, why is it that class functions don't create memory cycles but instance functions do?
I'm glad you asked:

For instance mehtods, for each instance that you reach out to, there is a new memory location and generate a new memory cycle which would persist deallocations.

For class methods, for each time you reach out to the class/type methods you reach out to the same class/type method, and while you persist that class method, you won't be creating it over and over, it is only created once and done!

In objective-C (and C++) type methods:

When the app starts up, the system can fairly safely just pre-allocate ALL the instructions
for those type methods into memory along with their class pointers
so there’s little to no overhead calling those over and over and over again.

I imagine swift is doing the same thing

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.

Why there is no `self` in the closure in the function `makeConstraints` by SnapKit?

public func makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
ConstraintMaker.makeConstraints(item: self.view, closure: closure)
}

Because the closure is not @escaping,so it means the closure will just run in the function. When the function over the closure will be released.
Only the function can hold the closure.

Implicit parameters in trailing closure

In

doMathOperation(4, 5, operation: multiply)

...you are being asked for a function that takes two Double parameters, and multiply is the name of just such a function, so it compiles and works.

In

doMathOperation(4, 5) { ... }

the curly braces themselves are the (body of the) function that takes two Double parameters. It makes no sense to put the name of another such function inside the curly braces.

But of course you are free to call any function you like, passing along the parameters that were passed to you; hence this works:

doMathOperation(4, 5) { multiply($0,$1) }

So, just to sum up: In the first one

doMathOperation(4, 5, operation: multiply)

there is one function, multiply, and 4 and 5 are passed to it. In the second one

doMathOperation(4, 5) { multiply($0,$1) }

there are two functions, "anonymous" (the curly braces) and multiply, and the 4 and 5 are passed into the first one and then it calls the second one.

Swift : Converting inline to trailing closures in function

Your parameters go inside the closure, and since there's just the one argument, you can even leave out the parentheses:

rest?.queryAllFlightsWithClosure {
(response: NSURLResponse!, data: NSData!, error: NSError!) in

// code ...
}

If you're going to be accessing self or any properties inside the closure, you'll want to include self in a capture list, like this:

rest?.queryAllFlightsWithClosure {
[weak self] (response: NSURLResponse!, data: NSData!, error: NSError!) in

// code ...

// note that self is optional inside this closure b/c of [weak self]
self?.doSomething()
}

Swift closure syntax using { ... in }

This is simplified syntax of trailing closure, so

Path { path in
...
}

is just the same as

Path( { (path) in
...
})

of used Path constructor

/// Initializes to an empty path then calls `callback` to add
/// the initial elements.
public init(_ callback: (inout Path) -> ())

By the way, this syntax is widely used in SwiftUI, so you will see the same in VStack { .. }, GeometryReader { g in ... }, ScrollView { ... } and almost all others UI elements of SwfitUI framework.



Related Topics



Leave a reply



Submit