How to Exit a Function Scope from Inner Function Using Swift

How to exit a function scope from inner function using Swift?

This is basically what Swift's error handling does:

func outer() throws
{
try inner()
print("Unreachable")
}

struct DoNotContinue : Error {}

func inner() throws
{
throw DoNotContinue()
}

do { try outer() }
catch _ { print("Skipped the unreachable") }

Note, of course, that the caller still has control over this: it could catch the thrown error itself instead of just exiting.

problem with this approach is that it can clutter your code

There's a much more serious problem with allowing callees to directly exit their callers, and that is that the flow of control very quickly becomes incomprehensible. Imagine that you have a couple of layers of this. Reading the top-level function, you no longer have any clear idea what can happen. You must yourself recurse into every callee's callee to make sure that the original code will continue on its course.

How to exit GUARD outside and inside a function - Swift

If the condition in your guard statement is not met, the else branch has to exit the current scope. return can only be used inside functions, as the error message shows, but return is not the only way to exit scope.

You can use throw outside functions as well and if the guard statement is in a loop, you can also use break or continue.

return valid in functions:

func testGuard(){
guard 2+2 == 4 else {
print("The universe makes no sense")
return // this is mandatory!
}
print("We can continue with our daily lives")
}

throw valid outside of function as well:

guard 2+2 == 4 else { throw NSError() }

break valid in loops:

for i in 1..<5 {
guard i < 5 else {
break
}
}

continue valid in loops:

for someObject in someArray { 
guard let someProperty = someObject.someOptionalProperty else {
continue
}
}

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 and throw both exit the function/method
  • continue 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 in if scopes.

Additionally, you may exit the scope by calling a function that returns Never, such as fatalError.

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
}
}

Swift - Exit function with background thread inside

As far as I know if you want to stop execution of for loop which is running on background thread, then you have to stop it from background thread itself which you are trying to stop from main thread block of code. try something line below :

func doSomething() {

var continueForLoop = true

DispatchQueue.global(qos: .userInteractive).async {
for ... {
if ... && continueForLoop{
...
DispatchQueue.main.sync {
//Update UI
...

if ... {
// Show UIAlert
//Exit function
continueForLoop = false
}
}
}else{
break;
}
}
}

}

P.S. to understand multithreading in iOS go thought this link : iOS Concurrency Note: try to understand the multithreading part only as code contains old swift syntaxes.

Function inside Function retain cycle

Just assign your closure to a local variable. At that point, extracting out dismiss is pointless, so just inline it:

private func setupDismissCallbacks() {     
let dismissCallback: () -> Void = { [weak self] in
guard let self = self else { return }
self.videoExporter?.cancel()
self.rootViewController.dismiss(animated: true, completion: nil)
self.delegate?.childCoordinatorDidFinish(self)
}

saveModalViewController.onButtonDismiss = dismissCallback
saveModalViewController.onDimmedAreaDismiss = dismissCallback
}


Related Topics



Leave a reply



Submit