Reputation:
I wonder why the tag noescape
isn't automatically detected and it needs to be explicitly applied.
In fact, it is somehow detected at compile time, because trying to add the @noescape tag to a func with escaping closures results in an error.
So the question is why... why noescape
needs to be explicitly added and Apple did not create it to be automatically added when it is needed?
Upvotes: 0
Views: 838
Reputation: 126157
Edit: Swift 3 makes a few changes here:
@noescape
to your function declarations that take closures as parameters if you want to require non-escaping closures. (Instead, you have to apply @escaping
in cases where you do plan to store a closure past the return of your function.)@escaping completionHandler: (Bool, Error) -> Void
, it's completionHandler: @escaping (Bool, Error) -> Void
.It's kinda hard to rewrite my whole answer to reflect that, so I'll leave it here for now... read on for the whys behind escaping-ness, just remember to invert noescape/escaping declarations. :) Or read about Escaping Closures in the Swift 3 version of The Swift Programming Language.
@noescape
isn't just a hint for compiler optimizations; it's part of the interface that a function declaration presents to callers. Whether a parameter to a function is declared @noescape
or allows escaping closures changes how a caller of that function writes the closure they pass as the parameter.
For example, given the function (from SequenceType
):
func filter(@noescape includeElement: (Self.Generator.Element) throws -> Bool) rethrows -> [Self.Generator.Element]
If I wanted to filter a collection based on some criteria that requires calling a method on self
, I know I can safely do that without worrying about whether the closure will capture self
and create a retain cycle.
// horribly contrived example
class Foo {
var things: [Thing]
func isCurrentlyAwesomeThing(thing: Thing) -> Bool { /*...*/ }
func thingsThatAreAwesomeRightNow() -> [Thing] {
return things.filter {
return isCurrentlyAwesomeThing($0)
}
}
}
If filter
permitted an escaping closure, the closure that calls isCurrentlyAwesomeThing()
would capture self
. (And thus require that method to be called with an explicit self.
prefix.) And if the implementation of filter
actually saved the closure beyond the runtime of that function, there'd be a memory leak because the closure retains self
and self
retains the array whose filter
function received the closure.
When you call a function whose closure parameters aren't declared @noescape
, you have to account for that possibility. This is why you see calls that add a [weak self]
capture list and a strong redeclaration inside the closure to make sure self
doesn't get deallocated during the closure. (Or at least an [unowned self]
in cases where you're reasonably certain the closure won't persist longer than self
.)
If closure parameters weren't able to be decorated as @noescape
(or as non-escaping through the absence of that decorator), you wouldn't know when calling a function that takes a closure whether you have to be careful about what that closure captures.
Upvotes: 2
Reputation: 149
If you use any function parameter as a noescape you can't able store in another closure, you can't able use dispatch_asynch and you can't able to call non-noescape closure from the noescape closure
The scope of the noescape attribute it should be with in the that closure
Upvotes: 0