YYThreadSafeDictionary.m 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. //
  2. // YYThreadSafeDictionary.m
  3. // YYKit <https://github.com/ibireme/YYKit>
  4. //
  5. // Created by ibireme on 14/10/21.
  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 "YYThreadSafeDictionary.h"
  12. #import "NSDictionary+YYAdd.h"
  13. #define INIT(...) self = super.init; \
  14. if (!self) return nil; \
  15. __VA_ARGS__; \
  16. if (!_dic) return nil; \
  17. _lock = dispatch_semaphore_create(1); \
  18. return self;
  19. #define LOCK(...) dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER); \
  20. __VA_ARGS__; \
  21. dispatch_semaphore_signal(_lock);
  22. @implementation YYThreadSafeDictionary {
  23. NSMutableDictionary *_dic; //Subclass a class cluster...
  24. dispatch_semaphore_t _lock;
  25. }
  26. #pragma mark - init
  27. - (instancetype)init {
  28. INIT(_dic = [[NSMutableDictionary alloc] init]);
  29. }
  30. - (instancetype)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys {
  31. INIT(_dic = [[NSMutableDictionary alloc] initWithObjects:objects forKeys:keys]);
  32. }
  33. - (instancetype)initWithCapacity:(NSUInteger)capacity {
  34. INIT(_dic = [[NSMutableDictionary alloc] initWithCapacity:capacity]);
  35. }
  36. - (instancetype)initWithObjects:(const id[])objects forKeys:(const id <NSCopying>[])keys count:(NSUInteger)cnt {
  37. INIT(_dic = [[NSMutableDictionary alloc] initWithObjects:objects forKeys:keys count:cnt]);
  38. }
  39. - (instancetype)initWithDictionary:(NSDictionary *)otherDictionary {
  40. INIT(_dic = [[NSMutableDictionary alloc] initWithDictionary:otherDictionary]);
  41. }
  42. - (instancetype)initWithDictionary:(NSDictionary *)otherDictionary copyItems:(BOOL)flag {
  43. INIT(_dic = [[NSMutableDictionary alloc] initWithDictionary:otherDictionary copyItems:flag]);
  44. }
  45. #pragma mark - method
  46. - (NSUInteger)count {
  47. LOCK(NSUInteger c = _dic.count); return c;
  48. }
  49. - (id)objectForKey:(id)aKey {
  50. LOCK(id o = [_dic objectForKey:aKey]); return o;
  51. }
  52. - (NSEnumerator *)keyEnumerator {
  53. LOCK(NSEnumerator * e = [_dic keyEnumerator]); return e;
  54. }
  55. - (NSArray *)allKeys {
  56. LOCK(NSArray * a = [_dic allKeys]); return a;
  57. }
  58. - (NSArray *)allKeysForObject:(id)anObject {
  59. LOCK(NSArray * a = [_dic allKeysForObject:anObject]); return a;
  60. }
  61. - (NSArray *)allValues {
  62. LOCK(NSArray * a = [_dic allValues]); return a;
  63. }
  64. - (NSString *)description {
  65. LOCK(NSString * d = [_dic description]); return d;
  66. }
  67. - (NSString *)descriptionInStringsFileFormat {
  68. LOCK(NSString * d = [_dic descriptionInStringsFileFormat]); return d;
  69. }
  70. - (NSString *)descriptionWithLocale:(id)locale {
  71. LOCK(NSString * d = [_dic descriptionWithLocale:locale]); return d;
  72. }
  73. - (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level {
  74. LOCK(NSString * d = [_dic descriptionWithLocale:locale indent:level]); return d;
  75. }
  76. - (BOOL)isEqualToDictionary:(NSDictionary *)otherDictionary {
  77. if (otherDictionary == self) return YES;
  78. if ([otherDictionary isKindOfClass:YYThreadSafeDictionary.class]) {
  79. YYThreadSafeDictionary *other = (id)otherDictionary;
  80. BOOL isEqual;
  81. dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
  82. dispatch_semaphore_wait(other->_lock, DISPATCH_TIME_FOREVER);
  83. isEqual = [_dic isEqual:other->_dic];
  84. dispatch_semaphore_signal(other->_lock);
  85. dispatch_semaphore_signal(_lock);
  86. return isEqual;
  87. }
  88. return NO;
  89. }
  90. - (NSEnumerator *)objectEnumerator {
  91. LOCK(NSEnumerator * e = [_dic objectEnumerator]); return e;
  92. }
  93. - (NSArray *)objectsForKeys:(NSArray *)keys notFoundMarker:(id)marker {
  94. LOCK(NSArray * a = [_dic objectsForKeys:keys notFoundMarker:marker]); return a;
  95. }
  96. - (NSArray *)keysSortedByValueUsingSelector:(SEL)comparator {
  97. LOCK(NSArray * a = [_dic keysSortedByValueUsingSelector:comparator]); return a;
  98. }
  99. - (void)getObjects:(id __unsafe_unretained[])objects andKeys:(id __unsafe_unretained[])keys {
  100. LOCK([_dic getObjects:objects andKeys:keys]);
  101. }
  102. - (id)objectForKeyedSubscript:(id)key {
  103. LOCK(id o = [_dic objectForKeyedSubscript:key]); return o;
  104. }
  105. - (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id key, id obj, BOOL *stop))block {
  106. LOCK([_dic enumerateKeysAndObjectsUsingBlock:block]);
  107. }
  108. - (void)enumerateKeysAndObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (^)(id key, id obj, BOOL *stop))block {
  109. LOCK([_dic enumerateKeysAndObjectsWithOptions:opts usingBlock:block]);
  110. }
  111. - (NSArray *)keysSortedByValueUsingComparator:(NSComparator)cmptr {
  112. LOCK(NSArray * a = [_dic keysSortedByValueUsingComparator:cmptr]); return a;
  113. }
  114. - (NSArray *)keysSortedByValueWithOptions:(NSSortOptions)opts usingComparator:(NSComparator)cmptr {
  115. LOCK(NSArray * a = [_dic keysSortedByValueWithOptions:opts usingComparator:cmptr]); return a;
  116. }
  117. - (NSSet *)keysOfEntriesPassingTest:(BOOL (^)(id key, id obj, BOOL *stop))predicate {
  118. LOCK(NSSet * a = [_dic keysOfEntriesPassingTest:predicate]); return a;
  119. }
  120. - (NSSet *)keysOfEntriesWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL (^)(id key, id obj, BOOL *stop))predicate {
  121. LOCK(NSSet * a = [_dic keysOfEntriesWithOptions:opts passingTest:predicate]); return a;
  122. }
  123. #pragma mark - mutable
  124. - (void)removeObjectForKey:(id)aKey {
  125. LOCK([_dic removeObjectForKey:aKey]);
  126. }
  127. - (void)setObject:(id)anObject forKey:(id <NSCopying> )aKey {
  128. LOCK([_dic setObject:anObject forKey:aKey]);
  129. }
  130. - (void)addEntriesFromDictionary:(NSDictionary *)otherDictionary {
  131. LOCK([_dic addEntriesFromDictionary:otherDictionary]);
  132. }
  133. - (void)removeAllObjects {
  134. LOCK([_dic removeAllObjects]);
  135. }
  136. - (void)removeObjectsForKeys:(NSArray *)keyArray {
  137. LOCK([_dic removeObjectsForKeys:keyArray]);
  138. }
  139. - (void)setDictionary:(NSDictionary *)otherDictionary {
  140. LOCK([_dic setDictionary:otherDictionary]);
  141. }
  142. - (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying> )key {
  143. LOCK([_dic setObject:obj forKeyedSubscript:key]);
  144. }
  145. #pragma mark - protocol
  146. - (id)copyWithZone:(NSZone *)zone {
  147. return [self mutableCopyWithZone:zone];
  148. }
  149. - (id)mutableCopyWithZone:(NSZone *)zone {
  150. LOCK(id copiedDictionary = [[self.class allocWithZone:zone] initWithDictionary:_dic]);
  151. return copiedDictionary;
  152. }
  153. - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
  154. objects:(id __unsafe_unretained[])stackbuf
  155. count:(NSUInteger)len {
  156. LOCK(NSUInteger count = [_dic countByEnumeratingWithState:state objects:stackbuf count:len]);
  157. return count;
  158. }
  159. - (BOOL)isEqual:(id)object {
  160. if (object == self) return YES;
  161. if ([object isKindOfClass:YYThreadSafeDictionary.class]) {
  162. YYThreadSafeDictionary *other = object;
  163. BOOL isEqual;
  164. dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
  165. dispatch_semaphore_wait(other->_lock, DISPATCH_TIME_FOREVER);
  166. isEqual = [_dic isEqual:other->_dic];
  167. dispatch_semaphore_signal(other->_lock);
  168. dispatch_semaphore_signal(_lock);
  169. return isEqual;
  170. }
  171. return NO;
  172. }
  173. - (NSUInteger)hash {
  174. LOCK(NSUInteger hash = [_dic hash]);
  175. return hash;
  176. }
  177. #pragma mark - custom methods for NSDictionary(YYAdd)
  178. - (NSDictionary *)entriesForKeys:(NSArray *)keys {
  179. LOCK(NSDictionary * dic = [_dic entriesForKeys:keys]) return dic;
  180. }
  181. - (NSString *)jsonStringEncoded {
  182. LOCK(NSString * s = [_dic jsonStringEncoded]) return s;
  183. }
  184. - (NSString *)jsonPrettyStringEncoded {
  185. LOCK(NSString * s = [_dic jsonPrettyStringEncoded]) return s;
  186. }
  187. - (id)popObjectForKey:(id)aKey {
  188. LOCK(id o = [_dic popObjectForKey:aKey]) return o;
  189. }
  190. - (NSDictionary *)popEntriesForKeys:(NSArray *)keys {
  191. LOCK(NSDictionary * d = [_dic popEntriesForKeys:keys]) return d;
  192. }
  193. @end