EXTScope.h 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  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. rac_keywordify \
  31. __strong rac_cleanupBlock_t metamacro_concat(rac_exitBlock_, __LINE__) __attribute__((cleanup(rac_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. rac_keywordify \
  44. metamacro_foreach_cxt(rac_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. rac_keywordify \
  51. metamacro_foreach_cxt(rac_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. rac_keywordify \
  75. _Pragma("clang diagnostic push") \
  76. _Pragma("clang diagnostic ignored \"-Wshadow\"") \
  77. metamacro_foreach(rac_strongify_,, __VA_ARGS__) \
  78. _Pragma("clang diagnostic pop")
  79. /*** implementation details follow ***/
  80. typedef void (^rac_cleanupBlock_t)();
  81. static inline void rac_executeCleanupBlock (__strong rac_cleanupBlock_t *block) {
  82. (*block)();
  83. }
  84. #define rac_weakify_(INDEX, CONTEXT, VAR) \
  85. CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR);
  86. #define rac_strongify_(INDEX, VAR) \
  87. __strong __typeof__(VAR) VAR = metamacro_concat(VAR, _weak_);
  88. // Details about the choice of backing keyword:
  89. //
  90. // The use of @try/@catch/@finally can cause the compiler to suppress
  91. // return-type warnings.
  92. // The use of @autoreleasepool {} is not optimized away by the compiler,
  93. // resulting in superfluous creation of autorelease pools.
  94. //
  95. // Since neither option is perfect, and with no other alternatives, the
  96. // compromise is to use @autorelease in DEBUG builds to maintain compiler
  97. // analysis, and to use @try/@catch otherwise to avoid insertion of unnecessary
  98. // autorelease pools.
  99. #if DEBUG
  100. #define rac_keywordify autoreleasepool {}
  101. #else
  102. #define rac_keywordify try {} @catch (...) {}
  103. #endif