Swift - Exit outer function from closure
Swift does not have non-local returns from closures. In other words, there is no direct way to return out of multiple levels. This only works with inlined functions in Kotlin, but Swift does not have this distinction.
There are other collection methods which stop once an element is found, for example index(where:)
.
func lookForLetter(letter: String, letters: [String]) {
guard let _ = letters.index(where: { (l) in
if l == letter {
print("Found");
return true
}
print(l)
return false
}) else {
print("Completed")
return
}
}
Can swift exit out of the root closure?
No there is not. Closures run in self-contained environments. For all you know, by the time that closure is executed, the thread on which test()
was called is no longer executing the test()
method.
Swift closure return from function
You'll need to use some other mechanism. Perhaps return a bool to say you should return straight away.
func synchronized(_ object: AnyObject, block: () -> Bool) -> Bool
{
objc_sync_enter(object)
defer { objc_sync_exit(object) }
return block()
}
public func stopRunning() {
guard synchronized( self, block: {
if status != .finished {
return false//<--Need to return from the function here, not just closure
}
return true
})
else { return }
...
...
}
Use break into closures [Swift]
Desipte it's very important to know count of images , you can use this
func getImages(_ i:Int) {
let downloadURL = URL(string: "serverURL")
Database.downloadImage(withURL: downloadURL!) { (image) in
if let img = image {
self.imagesArray.append(img)
self.collectionView?.reloadData()
getImages(i+1)
}
else {
print("image is nil final call")
}
}
}
}
Also may be the download is dependent on i as not to make an infinite loop
Is there a way to break from an array's reduce function in Swift?
As others have suggested, you can use contains
for this purpose:
var flags = [false, false, true, false, false, true, false]
contains(flags, true) //--> true
Another option is to use find
to search for the first instance of what you're looking for, in this case true
:
var flags = [false, false, true, false, false, true, false]
find(flags, true) // --> 2, returns nil if not found
let containsTrue = (find(flags, true) != nil)
Edit: Newer versions of Swift expose these functions on the related collection protocols instead of global functions.
var flags = [false, false, true, false, false, true, false]
flags.contains(where: { $0 == true })
flags.contains(true) // if checking for a specific element
let index = flags.firstIndex(where: ${ $0 == true }) // --> 2
Swift Closures in for loop
You can use a DispatchGroup
for this. It works like a counted semaphore. You can increase the count by calling enter
and decrease the count by calling leave
. You can schedule a closure to be executed when the count reaches 0 using notify
:
let dispatchGroup = DispatchGroup()
var noOfTimes = 10
for i in 0..<noOfTimes {
dispatchGroup.enter() // Enter the dispatch group
someVariable.someClosure {
result in
// Process result
...
dispatchGroup.leave() // Exit dispatch group
}
}
dispatchGroup.notify(queue: DispatchQueue.main, execute: {
print("All Done")
})
If the Swift 'guard' statement must exit scope, what is the definition of scope?
It is totally possible to do what you envision, it just happens to not be what that particular code does. return
always exits a method, not the local scope. To do what you wish, you can use a label, and break
:
func testGuardControlFlow () {
let x = 2
let y = 2
func embededFunc () {
breakLabel:
if y == 2 {
guard x == 1 else {
print("oops, number is not 1")
break breakLabel
}
print ("from in embededFunc")
}
print ("I still want this to print even if x != 1")
}
embededFunc()
print("Great, return still allows this to be printed.")
}
testGuardControlFlow()
To add on to vadian's answer:
guard
forces you to exit the scope using a control transfer statement. There are 4 available to you:
return
andthrow
both exit the function/methodcontinue
can be used within loops (while
/for
/repeat-while
)break
can be used in loops (while
/for
/repeat-while
) to exit the immediate scope. Specifying a label to break to will allow you to exit multiple scopes at once (e.g. breaking out of nested loop structure). When using a label,break
can also be used inif
scopes.
Additionally, you may exit the scope by calling a function that returns Never
, such as fatalError
.
How do I access variables that are inside closures in Swift?
var dict: NSDictionary! // Declared in the main thread
The closure is then completed asynchronously so the main thread doesn't wait for it, so
println(dict)
is called before the closure has actually finished. If you want to complete another function using dict then you will need to call that function from within the closure, you can move it into the main thread if you like though, you would do this if you are going to be affecting UI.
var dict: NSDictionary!
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {(response, data, error) in
var jsonError: NSError?
let json = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &jsonError) as? NSDictionary
dict = json
//dispatch_async(dispatch_get_main_queue()) { //uncomment for main thread
self.myFunction(dict!)
//} //uncomment for main thread
})
func myFunction(dictionary: NSDictionary) {
println(dictionary)
}
Do capture lists of inner closures need to redeclare `self` as `weak` or `unowned`?
The [weak self]
in anotherFunctionWithTrailingClosure
is not needed.
You can empirically test this:
class Experiment {
func someFunctionWithTrailingClosure(closure: @escaping () -> Void) {
print("starting", #function)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
closure()
print("finishing", #function)
}
}
func anotherFunctionWithTrailingClosure(closure: @escaping () -> Void) {
print("starting", #function)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
closure()
print("finishing", #function)
}
}
func doSomething() {
print(#function)
}
func testCompletionHandlers() {
someFunctionWithTrailingClosure { [weak self] in
self?.anotherFunctionWithTrailingClosure { // [weak self] in
self?.doSomething()
}
}
}
// go ahead and add `deinit`, so I can see when this is deallocated
deinit {
print("deinit")
}
}
And then:
func performExperiment() {
DispatchQueue.global().async {
let obj = Experiment()
obj.testCompletionHandlers()
// sleep long enough for `anotherFunctionWithTrailingClosure` to start, but not yet call its completion handler
Thread.sleep(forTimeInterval: 1.5)
}
}
If you do this, you will see that doSomething
is never called and that deinit
is called before anotherFunctionWithTrailingClosure
calls its closure.
That having been said, I might still be inclined to use the [weak self]
syntax on anotherFunctionWithTrailingClosure
to make my intent explicit.
Related Topics
How to Add 3D Shapes in Swift Ui
Custom Annotation Showing Same Image for All Different Types of Poi'S
Attrackingmanager Stopped Working in iOS 15
Set Uitextfield Placeholder Color Programmatically
How to Set the iOS13 Uisegmentedcontrol Backgroundcolor to White
How to Skip Iterations of a For-In Loop (Swift 3)
Why Can't I Use Self in a Func Swift
Why Are Uiscreen.Bounds Incorrect in iOS11
Type Check Operator (Is) for Check VS Homogenous Protocol: Why Can This Be Done for Optionals
Swift Tdd & Async Urlsession - How to Test
Error "No Such Module" When Installed Framework with Pod in Swift 3
Adding Index List and Section Headers to Translated Tableview
Is There a Github Markdown Language Identifier for Swift Code
What Does "Arg = Exploded" Mean in Swift Crash Log
Toolbar Is Deleting My Back Button in the Navigationview
Overriding Generic Function Error in Swift
How to Properly Calculate 1 Second with Deltatime in Swift
Sf Symbols Hierarchical, Palette, and Multicolor Rendering Mode Colors