EXTScope.h 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. //
  2. // EXTScope.h
  3. // extobjc
  4. //
  5. // Created by Justin Spahr-Summers on 2011-05-04.
  6. // Copyright (C) 2012 Justin Spahr-Summers.
  7. // Released under the MIT license.
  8. //
  9. #import "metamacros.h"
  10. /**
  11. * \@onExit defines some code to be executed when the current scope exits. The
  12. * code must be enclosed in braces and terminated with a semicolon, and will be
  13. * executed regardless of how the scope is exited, including from exceptions,
  14. * \c goto, \c return, \c break, and \c continue.
  15. *
  16. * Provided code will go into a block to be executed later. Keep this in mind as
  17. * it pertains to memory management, restrictions on assignment, etc. Because
  18. * the code is used within a block, \c return is a legal (though perhaps
  19. * confusing) way to exit the cleanup block early.
  20. *
  21. * Multiple \@onExit statements in the same scope are executed in reverse
  22. * lexical order. This helps when pairing resource acquisition with \@onExit
  23. * statements, as it guarantees teardown in the opposite order of acquisition.
  24. *
  25. * @note This statement cannot be used within scopes defined without braces
  26. * (like a one line \c if). In practice, this is not an issue, since \@onExit is
  27. * a useless construct in such a case anyways.
  28. */
  29. #define onExit \
  30. try {} @finally {} \
  31. __strong mtl_cleanupBlock_t metamacro_concat(mtl_exitBlock_, __LINE__) __attribute__((cleanup(mtl_executeCleanupBlock), unused)) = ^
  32. /**
  33. * Creates \c __weak shadow variables for each of the variables provided as
  34. * arguments, which can later be made strong again with #strongify.
  35. *
  36. * This is typically used to weakly reference variables in a block, but then
  37. * ensure that the variables stay alive during the actual execution of the block
  38. * (if they were live upon entry).
  39. *
  40. * See #strongify for an example of usage.
  41. */
  42. #define weakify(...) \
  43. try {} @finally {} \
  44. metamacro_foreach_cxt(mtl_weakify_,, __weak, __VA_ARGS__)
  45. /**
  46. * Like #weakify, but uses \c __unsafe_unretained instead, for targets or
  47. * classes that do not support weak references.
  48. */
  49. #define unsafeify(...) \
  50. try {} @finally {} \
  51. metamacro_foreach_cxt(mtl_weakify_,, __unsafe_unretained, __VA_ARGS__)
  52. /**
  53. * Strongly references each of the variables provided as arguments, which must
  54. * have previously been passed to #weakify.
  55. *
  56. * The strong references created will shadow the original variable names, such
  57. * that the original names can be used without issue (and a significantly
  58. * reduced risk of retain cycles) in the current scope.
  59. *
  60. * @code
  61. id foo = [[NSObject alloc] init];
  62. id bar = [[NSObject alloc] init];
  63. @weakify(foo, bar);
  64. // this block will not keep 'foo' or 'bar' alive
  65. BOOL (^matchesFooOrBar)(id) = ^ BOOL (id obj){
  66. // but now, upon entry, 'foo' and 'bar' will stay alive until the block has
  67. // finished executing
  68. @strongify(foo, bar);
  69. return [foo isEqual:obj] || [bar isEqual:obj];
  70. };
  71. * @endcode
  72. */
  73. #define strongify(...) \
  74. try {} @finally {} \
  75. _Pragma("clang diagnostic push") \
  76. _Pragma("clang diagnostic ignored \"-Wshadow\"") \
  77. metamacro_foreach(mtl_strongify_,, __VA_ARGS__) \
  78. _Pragma("clang diagnostic pop")
  79. /*** implementation details follow ***/
  80. typedef void (^mtl_cleanupBlock_t)();
  81. void mtl_executeCleanupBlock (__strong mtl_cleanupBlock_t *block);
  82. #define mtl_weakify_(INDEX, CONTEXT, VAR) \
  83. CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR);
  84. #define mtl_strongify_(INDEX, VAR) \
  85. __strong __typeof__(VAR) VAR = metamacro_concat(VAR, _weak_);