YYThreadSafeArray.m 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. //
  2. // YYThreadSafeArray.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 "YYThreadSafeArray.h"
  12. #import "NSArray+YYAdd.h"
  13. #define INIT(...) self = super.init; \
  14. if (!self) return nil; \
  15. __VA_ARGS__; \
  16. if (!_arr) 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 YYThreadSafeArray {
  23. NSMutableArray *_arr; //Subclass a class cluster...
  24. dispatch_semaphore_t _lock;
  25. }
  26. #pragma mark - init
  27. - (instancetype)init {
  28. INIT(_arr = [[NSMutableArray alloc] init]);
  29. }
  30. - (instancetype)initWithCapacity:(NSUInteger)numItems {
  31. INIT(_arr = [[NSMutableArray alloc] initWithCapacity:numItems]);
  32. }
  33. - (instancetype)initWithArray:(NSArray *)array {
  34. INIT(_arr = [[NSMutableArray alloc] initWithArray:array]);
  35. }
  36. - (instancetype)initWithObjects:(const id[])objects count:(NSUInteger)cnt {
  37. INIT(_arr = [[NSMutableArray alloc] initWithObjects:objects count:cnt]);
  38. }
  39. - (instancetype)initWithContentsOfFile:(NSString *)path {
  40. INIT(_arr = [[NSMutableArray alloc] initWithContentsOfFile:path]);
  41. }
  42. - (instancetype)initWithContentsOfURL:(NSURL *)url {
  43. INIT(_arr = [[NSMutableArray alloc] initWithContentsOfURL:url]);
  44. }
  45. #pragma mark - method
  46. - (NSUInteger)count {
  47. LOCK(NSUInteger count = _arr.count); return count;
  48. }
  49. - (id)objectAtIndex:(NSUInteger)index {
  50. LOCK(id obj = [_arr objectAtIndex:index]); return obj;
  51. }
  52. - (NSArray *)arrayByAddingObject:(id)anObject {
  53. LOCK(NSArray * arr = [_arr arrayByAddingObject:anObject]); return arr;
  54. }
  55. - (NSArray *)arrayByAddingObjectsFromArray:(NSArray *)otherArray {
  56. LOCK(NSArray * arr = [_arr arrayByAddingObjectsFromArray:otherArray]); return arr;
  57. }
  58. - (NSString *)componentsJoinedByString:(NSString *)separator {
  59. LOCK(NSString * str = [_arr componentsJoinedByString:separator]); return str;
  60. }
  61. - (BOOL)containsObject:(id)anObject {
  62. LOCK(BOOL c = [_arr containsObject:anObject]); return c;
  63. }
  64. - (NSString *)description {
  65. LOCK(NSString * d = _arr.description); return d;
  66. }
  67. - (NSString *)descriptionWithLocale:(id)locale {
  68. LOCK(NSString * d = [_arr descriptionWithLocale:locale]); return d;
  69. }
  70. - (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level {
  71. LOCK(NSString * d = [_arr descriptionWithLocale:locale indent:level]); return d;
  72. }
  73. - (id)firstObjectCommonWithArray:(NSArray *)otherArray {
  74. LOCK(id o = [_arr firstObjectCommonWithArray:otherArray]); return o;
  75. }
  76. - (void)getObjects:(id __unsafe_unretained[])objects range:(NSRange)range {
  77. LOCK([_arr getObjects:objects range:range]);
  78. }
  79. - (NSUInteger)indexOfObject:(id)anObject {
  80. LOCK(NSUInteger i = [_arr indexOfObject:anObject]); return i;
  81. }
  82. - (NSUInteger)indexOfObject:(id)anObject inRange:(NSRange)range {
  83. LOCK(NSUInteger i = [_arr indexOfObject:anObject inRange:range]); return i;
  84. }
  85. - (NSUInteger)indexOfObjectIdenticalTo:(id)anObject {
  86. LOCK(NSUInteger i = [_arr indexOfObjectIdenticalTo:anObject]); return i;
  87. }
  88. - (NSUInteger)indexOfObjectIdenticalTo:(id)anObject inRange:(NSRange)range {
  89. LOCK(NSUInteger i = [_arr indexOfObjectIdenticalTo:anObject inRange:range]); return i;
  90. }
  91. - (id)firstObject {
  92. LOCK(id o = _arr.firstObject); return o;
  93. }
  94. - (id)lastObject {
  95. LOCK(id o = _arr.lastObject); return o;
  96. }
  97. - (NSEnumerator *)objectEnumerator {
  98. LOCK(NSEnumerator * e = [_arr objectEnumerator]); return e;
  99. }
  100. - (NSEnumerator *)reverseObjectEnumerator {
  101. LOCK(NSEnumerator * e = [_arr reverseObjectEnumerator]); return e;
  102. }
  103. - (NSData *)sortedArrayHint {
  104. LOCK(NSData * d = [_arr sortedArrayHint]); return d;
  105. }
  106. - (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context {
  107. LOCK(NSArray * arr = [_arr sortedArrayUsingFunction:comparator context:context]) return arr;
  108. }
  109. - (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context hint:(NSData *)hint {
  110. LOCK(NSArray * arr = [_arr sortedArrayUsingFunction:comparator context:context hint:hint]); return arr;
  111. }
  112. - (NSArray *)sortedArrayUsingSelector:(SEL)comparator {
  113. LOCK(NSArray * arr = [_arr sortedArrayUsingSelector:comparator]); return arr;
  114. }
  115. - (NSArray *)subarrayWithRange:(NSRange)range {
  116. LOCK(NSArray * arr = [_arr subarrayWithRange:range]) return arr;
  117. }
  118. - (void)makeObjectsPerformSelector:(SEL)aSelector {
  119. LOCK([_arr makeObjectsPerformSelector:aSelector]);
  120. }
  121. - (void)makeObjectsPerformSelector:(SEL)aSelector withObject:(id)argument {
  122. LOCK([_arr makeObjectsPerformSelector:aSelector withObject:argument]);
  123. }
  124. - (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes {
  125. LOCK(NSArray * arr = [_arr objectsAtIndexes:indexes]); return arr;
  126. }
  127. - (id)objectAtIndexedSubscript:(NSUInteger)idx {
  128. LOCK(id o = [_arr objectAtIndexedSubscript:idx]); return o;
  129. }
  130. - (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block {
  131. LOCK([_arr enumerateObjectsUsingBlock:block]);
  132. }
  133. - (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block {
  134. LOCK([_arr enumerateObjectsWithOptions:opts usingBlock:block]);
  135. }
  136. - (void)enumerateObjectsAtIndexes:(NSIndexSet *)s options:(NSEnumerationOptions)opts usingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block {
  137. LOCK([_arr enumerateObjectsAtIndexes:s options:opts usingBlock:block]);
  138. }
  139. - (NSUInteger)indexOfObjectPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate {
  140. LOCK(NSUInteger i = [_arr indexOfObjectPassingTest:predicate]); return i;
  141. }
  142. - (NSUInteger)indexOfObjectWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate {
  143. LOCK(NSUInteger i = [_arr indexOfObjectWithOptions:opts passingTest:predicate]); return i;
  144. }
  145. - (NSUInteger)indexOfObjectAtIndexes:(NSIndexSet *)s options:(NSEnumerationOptions)opts passingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate {
  146. LOCK(NSUInteger i = [_arr indexOfObjectAtIndexes:s options:opts passingTest:predicate]); return i;
  147. }
  148. - (NSIndexSet *)indexesOfObjectsPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate {
  149. LOCK(NSIndexSet * i = [_arr indexesOfObjectsPassingTest:predicate]); return i;
  150. }
  151. - (NSIndexSet *)indexesOfObjectsWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate {
  152. LOCK(NSIndexSet * i = [_arr indexesOfObjectsWithOptions:opts passingTest:predicate]); return i;
  153. }
  154. - (NSIndexSet *)indexesOfObjectsAtIndexes:(NSIndexSet *)s options:(NSEnumerationOptions)opts passingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate {
  155. LOCK(NSIndexSet * i = [_arr indexesOfObjectsAtIndexes:s options:opts passingTest:predicate]); return i;
  156. }
  157. - (NSArray *)sortedArrayUsingComparator:(NSComparator)cmptr {
  158. LOCK(NSArray * a = [_arr sortedArrayUsingComparator:cmptr]); return a;
  159. }
  160. - (NSArray *)sortedArrayWithOptions:(NSSortOptions)opts usingComparator:(NSComparator)cmptr {
  161. LOCK(NSArray * a = [_arr sortedArrayWithOptions:opts usingComparator:cmptr]); return a;
  162. }
  163. - (NSUInteger)indexOfObject:(id)obj inSortedRange:(NSRange)r options:(NSBinarySearchingOptions)opts usingComparator:(NSComparator)cmp {
  164. LOCK(NSUInteger i = [_arr indexOfObject:obj inSortedRange:r options:opts usingComparator:cmp]); return i;
  165. }
  166. #pragma mark - mutable
  167. - (void)addObject:(id)anObject {
  168. LOCK([_arr addObject:anObject]);
  169. }
  170. - (void)insertObject:(id)anObject atIndex:(NSUInteger)index {
  171. LOCK([_arr insertObject:anObject atIndex:index]);
  172. }
  173. - (void)removeLastObject {
  174. LOCK([_arr removeLastObject]);
  175. }
  176. - (void)removeObjectAtIndex:(NSUInteger)index {
  177. LOCK([_arr removeObjectAtIndex:index]);
  178. }
  179. - (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject {
  180. LOCK([_arr replaceObjectAtIndex:index withObject:anObject]);
  181. }
  182. - (void)addObjectsFromArray:(NSArray *)otherArray {
  183. LOCK([_arr addObjectsFromArray:otherArray]);
  184. }
  185. - (void)exchangeObjectAtIndex:(NSUInteger)idx1 withObjectAtIndex:(NSUInteger)idx2 {
  186. LOCK([_arr exchangeObjectAtIndex:idx1 withObjectAtIndex:idx2]);
  187. }
  188. - (void)removeAllObjects {
  189. LOCK([_arr removeAllObjects]);
  190. }
  191. - (void)removeObject:(id)anObject inRange:(NSRange)range {
  192. LOCK([_arr removeObject:anObject inRange:range]);
  193. }
  194. - (void)removeObject:(id)anObject {
  195. LOCK([_arr removeObject:anObject]);
  196. }
  197. - (void)removeObjectIdenticalTo:(id)anObject inRange:(NSRange)range {
  198. LOCK([_arr removeObjectIdenticalTo:anObject inRange:range]);
  199. }
  200. - (void)removeObjectIdenticalTo:(id)anObject {
  201. LOCK([_arr removeObjectIdenticalTo:anObject]);
  202. }
  203. - (void)removeObjectsInArray:(NSArray *)otherArray {
  204. LOCK([_arr removeObjectsInArray:otherArray]);
  205. }
  206. - (void)removeObjectsInRange:(NSRange)range {
  207. LOCK([_arr removeObjectsInRange:range]);
  208. }
  209. - (void)replaceObjectsInRange:(NSRange)range withObjectsFromArray:(NSArray *)otherArray range:(NSRange)otherRange {
  210. LOCK([_arr replaceObjectsInRange:range withObjectsFromArray:otherArray range:otherRange]);
  211. }
  212. - (void)replaceObjectsInRange:(NSRange)range withObjectsFromArray:(NSArray *)otherArray {
  213. LOCK([_arr replaceObjectsInRange:range withObjectsFromArray:otherArray]);
  214. }
  215. - (void)setArray:(NSArray *)otherArray {
  216. LOCK([_arr setArray:otherArray]);
  217. }
  218. - (void)sortUsingFunction:(NSInteger (*)(id, id, void *))compare context:(void *)context {
  219. LOCK([_arr sortUsingFunction:compare context:context]);
  220. }
  221. - (void)sortUsingSelector:(SEL)comparator {
  222. LOCK([_arr sortUsingSelector:comparator]);
  223. }
  224. - (void)insertObjects:(NSArray *)objects atIndexes:(NSIndexSet *)indexes {
  225. LOCK([_arr insertObjects:objects atIndexes:indexes]);
  226. }
  227. - (void)removeObjectsAtIndexes:(NSIndexSet *)indexes {
  228. LOCK([_arr removeObjectsAtIndexes:indexes]);
  229. }
  230. - (void)replaceObjectsAtIndexes:(NSIndexSet *)indexes withObjects:(NSArray *)objects {
  231. LOCK([_arr replaceObjectsAtIndexes:indexes withObjects:objects]);
  232. }
  233. - (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx {
  234. LOCK([_arr setObject:obj atIndexedSubscript:idx]);
  235. }
  236. - (void)sortUsingComparator:(NSComparator)cmptr {
  237. LOCK([_arr sortUsingComparator:cmptr]);
  238. }
  239. - (void)sortWithOptions:(NSSortOptions)opts usingComparator:(NSComparator)cmptr {
  240. LOCK([_arr sortWithOptions:opts usingComparator:cmptr]);
  241. }
  242. - (BOOL)isEqualToArray:(NSArray *)otherArray {
  243. if (otherArray == self) return YES;
  244. if ([otherArray isKindOfClass:YYThreadSafeArray.class]) {
  245. YYThreadSafeArray *other = (id)otherArray;
  246. BOOL isEqual;
  247. dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
  248. dispatch_semaphore_wait(other->_lock, DISPATCH_TIME_FOREVER);
  249. isEqual = [_arr isEqualToArray:other->_arr];
  250. dispatch_semaphore_signal(other->_lock);
  251. dispatch_semaphore_signal(_lock);
  252. return isEqual;
  253. }
  254. return NO;
  255. }
  256. #pragma mark - protocol
  257. - (id)copyWithZone:(NSZone *)zone {
  258. return [self mutableCopyWithZone:zone];
  259. }
  260. - (id)mutableCopyWithZone:(NSZone *)zone {
  261. LOCK(id copiedDictionary = [[self.class allocWithZone:zone] initWithArray:_arr]);
  262. return copiedDictionary;
  263. }
  264. - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
  265. objects:(id __unsafe_unretained[])stackbuf
  266. count:(NSUInteger)len {
  267. LOCK(NSUInteger count = [_arr countByEnumeratingWithState:state objects:stackbuf count:len]);
  268. return count;
  269. }
  270. - (BOOL)isEqual:(id)object {
  271. if (object == self) return YES;
  272. if ([object isKindOfClass:YYThreadSafeArray.class]) {
  273. YYThreadSafeArray *other = object;
  274. BOOL isEqual;
  275. dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
  276. dispatch_semaphore_wait(other->_lock, DISPATCH_TIME_FOREVER);
  277. isEqual = [_arr isEqual:other->_arr];
  278. dispatch_semaphore_signal(other->_lock);
  279. dispatch_semaphore_signal(_lock);
  280. return isEqual;
  281. }
  282. return NO;
  283. }
  284. - (NSUInteger)hash {
  285. LOCK(NSUInteger hash = [_arr hash]);
  286. return hash;
  287. }
  288. #pragma mark - custom methods for NSArray(YYAdd)
  289. - (id)randomObject {
  290. LOCK(id o = [_arr randomObject]) return o;
  291. }
  292. - (id)objectOrNilAtIndex:(NSUInteger)index {
  293. LOCK(id o = [_arr objectOrNilAtIndex:index]) return o;
  294. }
  295. - (void)removeFirstObject {
  296. LOCK([_arr removeFirstObject]);
  297. }
  298. - (id)popFirstObject {
  299. LOCK(id o = [_arr popFirstObject]) return o;
  300. }
  301. - (id)popLastObject {
  302. LOCK(id o = [_arr popLastObject]) return o;
  303. }
  304. - (void)appendObjects:(NSArray *)objects {
  305. LOCK([_arr appendObjects:objects]);
  306. }
  307. - (void)prependObjects:(NSArray *)objects {
  308. LOCK([_arr prependObjects:objects]);
  309. }
  310. - (void)insertObjects:(NSArray *)objects atIndex:(NSUInteger)index {
  311. LOCK([_arr insertObjects:objects atIndex:index]);
  312. }
  313. - (void)reverse {
  314. LOCK([_arr reverse]);
  315. }
  316. - (void)shuffle {
  317. LOCK([_arr shuffle]);
  318. }
  319. @end