What is the difference between a defer statement and an expression right before returning?

What is the difference between this:

_ = navigationController?.popViewController(animated: true) defer { let rootVC = navigationController?.topViewController as? RootViewVC rootVC?.openLink(url: url) } return 

and this:

 _ = navigationController?.popViewController(animated: true) let rootVC = navigationController?.topViewController as? RootViewVC rootVC?.openLink(url: url) return 

The Apple swift guideline says: “You use the defer statement to execute a set of instructions just before the code leaves the current block of code.” But still, I did not quite understand.

+12
source share
6 answers

What is the difference between a pending statement and a statement just before a return?

All the difference in the world. The defer is executed after return! This allows you to do things that cannot be done in any other way.

For example, you can return a value and then change it. Apple uses this trick quite regularly; here, for example, is the code from the sequence documentation showing how to write your own sequence:

 struct Countdown: Sequence, IteratorProtocol { var count: Int mutating func next() -> Int? { if count == 0 { return nil } else { defer { count -= 1 } return count } } } 

If you wrote it like

  count -= 1 return count 

... it would break; we do not want to decrease count and then return it, we want to return count and then decrease it.

In addition, as already indicated, the defer is executed no matter how you exit. And this works regardless of whether you exit the current scope, which may not include return at all; defer works for function body, while block, if construct, do block, and so on. The only return is not the only way to get out of such a sphere! Your method may have multiple return , and / or you may throw an error, and / or you may have break , etc. Etc., Or you can just reach the last line of scope; defer is executed whenever possible. Writing the same code “manually” to cover all possible outputs can be very error prone.

+28
source

There is really no difference in your example, but please look at this:

 func foo(url: URL) -> Int let fileDescriptor : CInt = open(url.path, O_EVTONLY); defer { close(fileDescriptor) } guard let bar = something1() else { return 1 } guard let baz = something2() else { return 2 } doSomethingElse(bar, baz) return 3 } 

close(fileDescriptor) always executed regardless of which line the function returns.

+14
source

the defer statement is used to execute part of the code exactly before execution departs from the last area.

For instance:

 func defer() { print("Beginning") var value: String? defer { if let v = value { print("Ending execution of \(v)") } } value = "defer function" print("Ending") } 

The first line to be printed: Start

Second line to be printed: Ending

And the last line to be printed: End the deferral function.

+7
source

Using defer avoids conditional cleanup at the end of the function.

Consider the following example:

 class Demo { var a : String init(_ a:String) { self.a = a } func finish() { print("Finishing \(a)") } } func play(_ n:Int) { let x = Demo("x") defer { x.finish() } if (n < 2) {return} let y = Demo("y") defer { y.finish() } if (n < 3) {return} let z = Demo("z") defer { z.finish() } } play(1) play(2) play(3) 

The play function creates one, two or three Demo objects depending on its parameter and calls finish on them at the end of the run. If the function returns from the middle, defer statements defer not executed, and finish not called for objects that are never created.

An alternative to this may require the use of options:

 func play(_ n:Int) { var x:Demo? = nil var y:Demo? = nil var z:Demo? = nil x = Demo("x") if (n >= 2) { y = Demo("y") } if (n >= 3) { z = Demo("z") } x?.finish() y?.finish() z?.finish() } 

This approach places all ads at the top and forces you to expand additional options later. defer code, on the other hand, allows you to write cleanup code next to code that performs initialization.

+4
source

Guard - Guard checks some condition and, if it evaluates to false, the else statement is executed, which usually exists as a method.

Defer - Defer will wait for the code block to execute until the current region (loop, method, etc.) exits.

0
source

I would like to emphasize that the "defer statement is executed after return"

 class Test { var value: Int = 0 { didSet { print("Value is now \(value)") } } func incrementor() -> Int { defer { print("In defer") value = value + 1 } print("Just before return") return value } } let test = Test() test.value = 1 print("Will call incrementor") let result = test.incrementor() print("Did increment with result \(result)") 

Console exit

 Value is now 1 Will call incrementor Just before return In defer Value is now 2 Did increment with result 1 

The delay is called after the return, therefore, the old value 1 was returned instead of the increased value 2 .

0
source

Source: https://habr.com/ru/post/1015341/


All Articles