YYKitMacro.h 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. //
  2. // YYKitMacro.h
  3. // YYKit <https://github.com/ibireme/YYKit>
  4. //
  5. // Created by ibireme on 13/3/29.
  6. // Copyright (c) 2015 ibireme.
  7. //
  8. // This source code is licensed under the MIT-style license found in the
  9. // LICENSE file in the root directory of this source tree.
  10. //
  11. #import <UIKit/UIKit.h>
  12. #import <sys/time.h>
  13. #import <pthread.h>
  14. #ifndef YYKitMacro_h
  15. #define YYKitMacro_h
  16. #ifdef __cplusplus
  17. #define YY_EXTERN_C_BEGIN extern "C" {
  18. #define YY_EXTERN_C_END }
  19. #else
  20. #define YY_EXTERN_C_BEGIN
  21. #define YY_EXTERN_C_END
  22. #endif
  23. YY_EXTERN_C_BEGIN
  24. #ifndef YY_CLAMP // return the clamped value
  25. #define YY_CLAMP(_x_, _low_, _high_) (((_x_) > (_high_)) ? (_high_) : (((_x_) < (_low_)) ? (_low_) : (_x_)))
  26. #endif
  27. #ifndef YY_SWAP // swap two value
  28. #define YY_SWAP(_a_, _b_) do { __typeof__(_a_) _tmp_ = (_a_); (_a_) = (_b_); (_b_) = _tmp_; } while (0)
  29. #endif
  30. #define YYAssertNil(condition, description, ...) NSAssert(!(condition), (description), ##__VA_ARGS__)
  31. #define YYCAssertNil(condition, description, ...) NSCAssert(!(condition), (description), ##__VA_ARGS__)
  32. #define YYAssertNotNil(condition, description, ...) NSAssert((condition), (description), ##__VA_ARGS__)
  33. #define YYCAssertNotNil(condition, description, ...) NSCAssert((condition), (description), ##__VA_ARGS__)
  34. #define YYAssertMainThread() NSAssert([NSThread isMainThread], @"This method must be called on the main thread")
  35. #define YYCAssertMainThread() NSCAssert([NSThread isMainThread], @"This method must be called on the main thread")
  36. /**
  37. Add this macro before each category implementation, so we don't have to use
  38. -all_load or -force_load to load object files from static libraries that only
  39. contain categories and no classes.
  40. More info: http://developer.apple.com/library/mac/#qa/qa2006/qa1490.html .
  41. *******************************************************************************
  42. Example:
  43. YYSYNTH_DUMMY_CLASS(NSString_YYAdd)
  44. */
  45. #ifndef YYSYNTH_DUMMY_CLASS
  46. #define YYSYNTH_DUMMY_CLASS(_name_) \
  47. @interface YYSYNTH_DUMMY_CLASS_ ## _name_ : NSObject @end \
  48. @implementation YYSYNTH_DUMMY_CLASS_ ## _name_ @end
  49. #endif
  50. /**
  51. Synthsize a dynamic object property in @implementation scope.
  52. It allows us to add custom properties to existing classes in categories.
  53. @param association ASSIGN / RETAIN / COPY / RETAIN_NONATOMIC / COPY_NONATOMIC
  54. @warning #import <objc/runtime.h>
  55. *******************************************************************************
  56. Example:
  57. @interface NSObject (MyAdd)
  58. @property (nonatomic, retain) UIColor *myColor;
  59. @end
  60. #import <objc/runtime.h>
  61. @implementation NSObject (MyAdd)
  62. YYSYNTH_DYNAMIC_PROPERTY_OBJECT(myColor, setMyColor, RETAIN, UIColor *)
  63. @end
  64. */
  65. #ifndef YYSYNTH_DYNAMIC_PROPERTY_OBJECT
  66. #define YYSYNTH_DYNAMIC_PROPERTY_OBJECT(_getter_, _setter_, _association_, _type_) \
  67. - (void)_setter_ : (_type_)object { \
  68. [self willChangeValueForKey:@#_getter_]; \
  69. objc_setAssociatedObject(self, _cmd, object, OBJC_ASSOCIATION_ ## _association_); \
  70. [self didChangeValueForKey:@#_getter_]; \
  71. } \
  72. - (_type_)_getter_ { \
  73. return objc_getAssociatedObject(self, @selector(_setter_:)); \
  74. }
  75. #endif
  76. /**
  77. Synthsize a dynamic c type property in @implementation scope.
  78. It allows us to add custom properties to existing classes in categories.
  79. @warning #import <objc/runtime.h>
  80. *******************************************************************************
  81. Example:
  82. @interface NSObject (MyAdd)
  83. @property (nonatomic, retain) CGPoint myPoint;
  84. @end
  85. #import <objc/runtime.h>
  86. @implementation NSObject (MyAdd)
  87. YYSYNTH_DYNAMIC_PROPERTY_CTYPE(myPoint, setMyPoint, CGPoint)
  88. @end
  89. */
  90. #ifndef YYSYNTH_DYNAMIC_PROPERTY_CTYPE
  91. #define YYSYNTH_DYNAMIC_PROPERTY_CTYPE(_getter_, _setter_, _type_) \
  92. - (void)_setter_ : (_type_)object { \
  93. [self willChangeValueForKey:@#_getter_]; \
  94. NSValue *value = [NSValue value:&object withObjCType:@encode(_type_)]; \
  95. objc_setAssociatedObject(self, _cmd, value, OBJC_ASSOCIATION_RETAIN); \
  96. [self didChangeValueForKey:@#_getter_]; \
  97. } \
  98. - (_type_)_getter_ { \
  99. _type_ cValue = { 0 }; \
  100. NSValue *value = objc_getAssociatedObject(self, @selector(_setter_:)); \
  101. [value getValue:&cValue]; \
  102. return cValue; \
  103. }
  104. #endif
  105. /**
  106. Synthsize a weak or strong reference.
  107. Example:
  108. @weakify(self)
  109. [self doSomething^{
  110. @strongify(self)
  111. if (!self) return;
  112. ...
  113. }];
  114. */
  115. #ifndef weakify
  116. #if DEBUG
  117. #if __has_feature(objc_arc)
  118. #define weakify(object) autoreleasepool{} __weak __typeof__(object) weak##_##object = object;
  119. #else
  120. #define weakify(object) autoreleasepool{} __block __typeof__(object) block##_##object = object;
  121. #endif
  122. #else
  123. #if __has_feature(objc_arc)
  124. #define weakify(object) try{} @finally{} {} __weak __typeof__(object) weak##_##object = object;
  125. #else
  126. #define weakify(object) try{} @finally{} {} __block __typeof__(object) block##_##object = object;
  127. #endif
  128. #endif
  129. #endif
  130. #ifndef strongify
  131. #if DEBUG
  132. #if __has_feature(objc_arc)
  133. #define strongify(object) autoreleasepool{} __typeof__(object) object = weak##_##object;
  134. #else
  135. #define strongify(object) autoreleasepool{} __typeof__(object) object = block##_##object;
  136. #endif
  137. #else
  138. #if __has_feature(objc_arc)
  139. #define strongify(object) try{} @finally{} __typeof__(object) object = weak##_##object;
  140. #else
  141. #define strongify(object) try{} @finally{} __typeof__(object) object = block##_##object;
  142. #endif
  143. #endif
  144. #endif
  145. /**
  146. Convert CFRange to NSRange
  147. @param range CFRange @return NSRange
  148. */
  149. static inline NSRange YYNSRangeFromCFRange(CFRange range) {
  150. return NSMakeRange(range.location, range.length);
  151. }
  152. /**
  153. Convert NSRange to CFRange
  154. @param range NSRange @return CFRange
  155. */
  156. static inline CFRange YYCFRangeFromNSRange(NSRange range) {
  157. return CFRangeMake(range.location, range.length);
  158. }
  159. /**
  160. Same as CFAutorelease(), compatible for iOS6
  161. @param arg CFObject @return same as input
  162. */
  163. static inline CFTypeRef YYCFAutorelease(CFTypeRef CF_RELEASES_ARGUMENT arg) {
  164. if (((long)CFAutorelease + 1) != 1) {
  165. return CFAutorelease(arg);
  166. } else {
  167. id __autoreleasing obj = CFBridgingRelease(arg);
  168. return (__bridge CFTypeRef)obj;
  169. }
  170. }
  171. /**
  172. Profile time cost.
  173. @param block code to benchmark
  174. @param complete code time cost (millisecond)
  175. Usage:
  176. YYBenchmark(^{
  177. // code
  178. }, ^(double ms) {
  179. NSLog("time cost: %.2f ms",ms);
  180. });
  181. */
  182. static inline void YYBenchmark(void (^block)(void), void (^complete)(double ms)) {
  183. // <QuartzCore/QuartzCore.h> version
  184. /*
  185. extern double CACurrentMediaTime (void);
  186. double begin, end, ms;
  187. begin = CACurrentMediaTime();
  188. block();
  189. end = CACurrentMediaTime();
  190. ms = (end - begin) * 1000.0;
  191. complete(ms);
  192. */
  193. // <sys/time.h> version
  194. struct timeval t0, t1;
  195. gettimeofday(&t0, NULL);
  196. block();
  197. gettimeofday(&t1, NULL);
  198. double ms = (double)(t1.tv_sec - t0.tv_sec) * 1e3 + (double)(t1.tv_usec - t0.tv_usec) * 1e-3;
  199. complete(ms);
  200. }
  201. static inline NSDate *_YYCompileTime(const char *data, const char *time) {
  202. NSString *timeStr = [[NSString alloc] initWithFormat:@"%s %s",data,time];
  203. NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
  204. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  205. [formatter setDateFormat:@"MMM dd yyyy HH:mm:ss"];
  206. [formatter setLocale:locale];
  207. return [formatter dateFromString:timeStr];
  208. }
  209. /**
  210. Get compile timestamp.
  211. @return A new date object set to the compile date and time.
  212. */
  213. #ifndef YYCompileTime
  214. // use macro to avoid compile warning when use pch file
  215. #define YYCompileTime() _YYCompileTime(__DATE__, __TIME__)
  216. #endif
  217. /**
  218. Returns a dispatch_time delay from now.
  219. */
  220. static inline dispatch_time_t dispatch_time_delay(NSTimeInterval second) {
  221. return dispatch_time(DISPATCH_TIME_NOW, (int64_t)(second * NSEC_PER_SEC));
  222. }
  223. /**
  224. Returns a dispatch_wall_time delay from now.
  225. */
  226. static inline dispatch_time_t dispatch_walltime_delay(NSTimeInterval second) {
  227. return dispatch_walltime(DISPATCH_TIME_NOW, (int64_t)(second * NSEC_PER_SEC));
  228. }
  229. /**
  230. Returns a dispatch_wall_time from NSDate.
  231. */
  232. static inline dispatch_time_t dispatch_walltime_date(NSDate *date) {
  233. NSTimeInterval interval;
  234. double second, subsecond;
  235. struct timespec time;
  236. dispatch_time_t milestone;
  237. interval = [date timeIntervalSince1970];
  238. subsecond = modf(interval, &second);
  239. time.tv_sec = second;
  240. time.tv_nsec = subsecond * NSEC_PER_SEC;
  241. milestone = dispatch_walltime(&time, 0);
  242. return milestone;
  243. }
  244. /**
  245. Whether in main queue/thread.
  246. */
  247. static inline bool dispatch_is_main_queue() {
  248. return pthread_main_np() != 0;
  249. }
  250. /**
  251. Submits a block for asynchronous execution on a main queue and returns immediately.
  252. */
  253. static inline void dispatch_async_on_main_queue(void (^block)()) {
  254. if (pthread_main_np()) {
  255. block();
  256. } else {
  257. dispatch_async(dispatch_get_main_queue(), block);
  258. }
  259. }
  260. /**
  261. Submits a block for execution on a main queue and waits until the block completes.
  262. */
  263. static inline void dispatch_sync_on_main_queue(void (^block)()) {
  264. if (pthread_main_np()) {
  265. block();
  266. } else {
  267. dispatch_sync(dispatch_get_main_queue(), block);
  268. }
  269. }
  270. /**
  271. Initialize a pthread mutex.
  272. */
  273. static inline void pthread_mutex_init_recursive(pthread_mutex_t *mutex, bool recursive) {
  274. #define YYMUTEX_ASSERT_ON_ERROR(x_) do { \
  275. __unused volatile int res = (x_); \
  276. assert(res == 0); \
  277. } while (0)
  278. assert(mutex != NULL);
  279. if (!recursive) {
  280. YYMUTEX_ASSERT_ON_ERROR(pthread_mutex_init(mutex, NULL));
  281. } else {
  282. pthread_mutexattr_t attr;
  283. YYMUTEX_ASSERT_ON_ERROR(pthread_mutexattr_init (&attr));
  284. YYMUTEX_ASSERT_ON_ERROR(pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE));
  285. YYMUTEX_ASSERT_ON_ERROR(pthread_mutex_init (mutex, &attr));
  286. YYMUTEX_ASSERT_ON_ERROR(pthread_mutexattr_destroy (&attr));
  287. }
  288. #undef YYMUTEX_ASSERT_ON_ERROR
  289. }
  290. YY_EXTERN_C_END
  291. #endif