How to use defer

#ifndef SWIFT_BASIC_DEFER_H
#define SWIFT_BASIC_DEFER_H
​
#include "llvm/ADT/ScopeExit.h"
​
namespace swift {
  namespace detail {
    struct DeferTask {};
    template<typename F>
    auto operator+(DeferTask, F &&fn) ->
        decltype(llvm::make_scope_exit(std::forward<F>(fn))) {
      return llvm::make_scope_exit(std::forward<F>(fn));
    }
  }
} // end namespace swift
​
​
#define DEFER_CONCAT_IMPL(x, y) x##y
#define DEFER_MACRO_CONCAT(x, y) DEFER_CONCAT_IMPL(x, y)
​
/// This macro is used to register a function / lambda to be run on exit from a
/// scope.  Its typical use looks like:
///
///   SWIFT_DEFER {
///     stuff
///   };
///
#define SWIFT_DEFER                                                            \
  auto DEFER_MACRO_CONCAT(defer_func, __COUNTER__) =                           \
      ::swift::detail::DeferTask() + [&]()
​
#endif // SWIFT_BASIC_DEFER_H

The above code is the declaration and implementation of defer in the Swift source code. We can intuitively see that the bottom layer is implemented in C++. We can regard the closure declared by defer as a variable within a function. According to the life cycle rules of local variables in C++, that is, LIFO (Last In First Out), the closure of defer declared last is the last It is released first, so it will be executed first.

When I interviewed Byte before, I was asked defer-related questions, such as life cycle, release order, and have you read the source code? Do you know its underlying implementation? for example:

func test() {
    defer { print("1") }
    defer { print("2") }
    print("3")
    defer{
      print(4)
    }
}

The output result is:

3 4 2 1

In line with our expectations.

Usage scenarios of defer

In actual development projects, when we use the database, we will need to close the database after opening it. However, there may be a lot of logical judgment operations such as if and guard. At this time, if you follow the logical line to find the end of function execution, there will inevitably be omissions. At this time, defer will be a very good choice. .

For another example , we will need to execute to close the graphics context UIGraphicsBeginImageContextWithOptions(imgSize, **false**, 0)after drawing.UIGraphicsEndImageContext()

UIGraphicsBeginImageContextWithOptions(imgSize, false, 0)
defer {
    /// 5. 
    UIGraphicsEndImageContext()
}
 // TODO something

Leave a Reply

Your email address will not be published. Required fields are marked *