appium-webdriveragent 3.9.2 → 3.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/PrivateHeaders/.DS_Store +0 -0
  2. package/PrivateHeaders/XCTest/XCTestManager_ManagerInterface-Protocol.h +3 -0
  3. package/README.md +0 -1
  4. package/WebDriverAgent.xcodeproj/project.pbxproj +56 -56
  5. package/WebDriverAgent.xcodeproj/project.xcworkspace/xcuserdata/elf.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  6. package/WebDriverAgent.xcodeproj/xcuserdata/elf.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +51 -0
  7. package/WebDriverAgent.xcodeproj/xcuserdata/{kazuaki.xcuserdatad → elf.xcuserdatad}/xcschemes/xcschememanagement.plist +23 -8
  8. package/WebDriverAgentLib/.DS_Store +0 -0
  9. package/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.h +0 -17
  10. package/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m +0 -16
  11. package/WebDriverAgentLib/Categories/XCUIElement+FBIsVisible.m +28 -14
  12. package/WebDriverAgentLib/Categories/XCUIElement+FBResolve.h +37 -0
  13. package/WebDriverAgentLib/Categories/XCUIElement+FBResolve.m +51 -0
  14. package/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m +8 -2
  15. package/WebDriverAgentLib/Commands/FBElementCommands.m +3 -1
  16. package/WebDriverAgentLib/Commands/FBOrientationCommands.m +20 -9
  17. package/WebDriverAgentLib/Commands/FBSessionCommands.m +119 -99
  18. package/WebDriverAgentLib/FBApplication.m +1 -1
  19. package/WebDriverAgentLib/Routing/FBElementCache.m +42 -11
  20. package/WebDriverAgentLib/Routing/FBResponsePayload.m +9 -3
  21. package/WebDriverAgentLib/Routing/FBSession.h +6 -0
  22. package/WebDriverAgentLib/Routing/FBSession.m +45 -55
  23. package/WebDriverAgentLib/Utilities/FBAlertsMonitor.h +1 -3
  24. package/WebDriverAgentLib/Utilities/FBAlertsMonitor.m +6 -13
  25. package/WebDriverAgentLib/Utilities/FBCapabilities.h +23 -0
  26. package/WebDriverAgentLib/Utilities/FBCapabilities.m +23 -0
  27. package/WebDriverAgentLib/Utilities/FBConfiguration.m +6 -1
  28. package/WebDriverAgentLib/Utilities/FBScreenshot.m +125 -14
  29. package/WebDriverAgentLib/Utilities/FBSettings.h +23 -23
  30. package/WebDriverAgentLib/Utilities/FBSettings.m +23 -23
  31. package/WebDriverAgentLib/Utilities/FBXCodeCompatibility.h +16 -0
  32. package/WebDriverAgentLib/Utilities/FBXCodeCompatibility.m +16 -0
  33. package/WebDriverAgentLib/Utilities/FBXPath.m +15 -44
  34. package/WebDriverAgentLib/Utilities/LRUCache/.DS_Store +0 -0
  35. package/WebDriverAgentLib/Utilities/LRUCache/LRUCache.h +59 -0
  36. package/WebDriverAgentLib/Utilities/LRUCache/LRUCache.m +104 -0
  37. package/WebDriverAgentLib/Utilities/LRUCache/LRUCacheNode.h +43 -0
  38. package/WebDriverAgentLib/Utilities/LRUCache/LRUCacheNode.m +59 -0
  39. package/WebDriverAgentLib/Vendor/.DS_Store +0 -0
  40. package/WebDriverAgentRunner/.DS_Store +0 -0
  41. package/WebDriverAgentRunner-Runner.app.zip +0 -0
  42. package/WebDriverAgentTests/IntegrationApp/Resources/.DS_Store +0 -0
  43. package/WebDriverAgentTests/IntegrationTests/FBSessionIntegrationTests.m +20 -16
  44. package/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m +2 -1
  45. package/WebDriverAgentTests/IntegrationTests/XCUIElementFBFindTests.m +11 -0
  46. package/WebDriverAgentTests/UnitTests/Doubles/FBApplicationDouble.h +3 -0
  47. package/WebDriverAgentTests/UnitTests/Doubles/FBApplicationDouble.m +15 -0
  48. package/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.h +1 -0
  49. package/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.m +1 -0
  50. package/WebDriverAgentTests/UnitTests/FBSessionTests.m +11 -1
  51. package/WebDriverAgentTests/UnitTests/FBXPathTests.m +3 -1
  52. package/WebDriverAgentTests/UnitTests_tvOS/Doubles/XCUIElementDouble.h +1 -0
  53. package/WebDriverAgentTests/UnitTests_tvOS/Doubles/XCUIElementDouble.m +1 -0
  54. package/package.json +3 -3
  55. package/WebDriverAgent.xcodeproj/project.xcworkspace/xcuserdata/kazuaki.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  56. package/WebDriverAgent.xcodeproj/project.xcworkspace/xcuserdata/kazuaki.xcuserdatad/WorkspaceSettings.xcsettings +0 -20
  57. package/WebDriverAgent.xcodeproj/xcuserdata/kazuaki.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +0 -906
  58. package/WebDriverAgentLib/Vendor/YYCache/YYCache.h +0 -206
  59. package/WebDriverAgentLib/Vendor/YYCache/YYCache.m +0 -140
  60. package/WebDriverAgentLib/Vendor/YYCache/YYDiskCache.h +0 -412
  61. package/WebDriverAgentLib/Vendor/YYCache/YYDiskCache.m +0 -462
  62. package/WebDriverAgentLib/Vendor/YYCache/YYKVStorage.h +0 -325
  63. package/WebDriverAgentLib/Vendor/YYCache/YYKVStorage.m +0 -1068
  64. package/WebDriverAgentLib/Vendor/YYCache/YYMemoryCache.h +0 -213
  65. package/WebDriverAgentLib/Vendor/YYCache/YYMemoryCache.m +0 -508
@@ -1,213 +0,0 @@
1
- //
2
- // YYMemoryCache.h
3
- // YYCache <https://github.com/ibireme/YYCache>
4
- //
5
- // Created by ibireme on 15/2/7.
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
-
12
- #import <Foundation/Foundation.h>
13
-
14
- NS_ASSUME_NONNULL_BEGIN
15
-
16
- /**
17
- YYMemoryCache is a fast in-memory cache that stores key-value pairs.
18
- In contrast to NSDictionary, keys are retained and not copied.
19
- The API and performance is similar to `NSCache`, all methods are thread-safe.
20
-
21
- YYMemoryCache objects differ from NSCache in a few ways:
22
-
23
- * It uses LRU (least-recently-used) to remove objects; NSCache's eviction method
24
- is non-deterministic.
25
- * It can be controlled by cost, count and age; NSCache's limits are imprecise.
26
- * It can be configured to automatically evict objects when receive memory
27
- warning or app enter background.
28
-
29
- The time of `Access Methods` in YYMemoryCache is typically in constant time (O(1)).
30
- */
31
- @interface YYMemoryCache : NSObject
32
-
33
- #pragma mark - Attribute
34
- ///=============================================================================
35
- /// @name Attribute
36
- ///=============================================================================
37
-
38
- /** The name of the cache. Default is nil. */
39
- @property (nullable, copy) NSString *name;
40
-
41
- /** The number of objects in the cache (read-only) */
42
- @property (atomic, readonly) NSUInteger totalCount;
43
-
44
- /** The total cost of objects in the cache (read-only). */
45
- @property (atomic, readonly) NSUInteger totalCost;
46
-
47
-
48
- #pragma mark - Limit
49
- ///=============================================================================
50
- /// @name Limit
51
- ///=============================================================================
52
-
53
- /**
54
- The maximum number of objects the cache should hold.
55
-
56
- @discussion The default value is NSUIntegerMax, which means no limit.
57
- This is not a strict limit—if the cache goes over the limit, some objects in the
58
- cache could be evicted later in backgound thread.
59
- */
60
- @property NSUInteger countLimit;
61
-
62
- /**
63
- The maximum total cost that the cache can hold before it starts evicting objects.
64
-
65
- @discussion The default value is NSUIntegerMax, which means no limit.
66
- This is not a strict limit—if the cache goes over the limit, some objects in the
67
- cache could be evicted later in backgound thread.
68
- */
69
- @property NSUInteger costLimit;
70
-
71
- /**
72
- The maximum expiry time of objects in cache.
73
-
74
- @discussion The default value is DBL_MAX, which means no limit.
75
- This is not a strict limit—if an object goes over the limit, the object could
76
- be evicted later in backgound thread.
77
- */
78
- @property NSTimeInterval ageLimit;
79
-
80
- /**
81
- The auto trim check time interval in seconds. Default is 5.0.
82
-
83
- @discussion The cache holds an internal timer to check whether the cache reaches
84
- its limits, and if the limit is reached, it begins to evict objects.
85
- */
86
- @property NSTimeInterval autoTrimInterval;
87
-
88
- /**
89
- If `YES`, the cache will remove all objects when the app receives a memory warning.
90
- The default value is `YES`.
91
- */
92
- @property BOOL shouldRemoveAllObjectsOnMemoryWarning;
93
-
94
- /**
95
- If `YES`, The cache will remove all objects when the app enter background.
96
- The default value is `YES`.
97
- */
98
- @property BOOL shouldRemoveAllObjectsWhenEnteringBackground;
99
-
100
- /**
101
- A block to be executed when the app receives a memory warning.
102
- The default value is nil.
103
- */
104
- @property (nullable, copy) void(^didReceiveMemoryWarningBlock)(YYMemoryCache *cache);
105
-
106
- /**
107
- A block to be executed when the app enter background.
108
- The default value is nil.
109
- */
110
- @property (nullable, copy) void(^didEnterBackgroundBlock)(YYMemoryCache *cache);
111
-
112
- /**
113
- If `YES`, the key-value pair will be released on main thread, otherwise on
114
- background thread. Default is NO.
115
-
116
- @discussion You may set this value to `YES` if the key-value object contains
117
- the instance which should be released in main thread (such as UIView/CALayer).
118
- */
119
- @property (atomic) BOOL releaseOnMainThread;
120
-
121
- /**
122
- If `YES`, the key-value pair will be released asynchronously to avoid blocking
123
- the access methods, otherwise it will be released in the access method
124
- (such as removeObjectForKey:). Default is YES.
125
- */
126
- @property (atomic) BOOL releaseAsynchronously;
127
-
128
-
129
- #pragma mark - Access Methods
130
- ///=============================================================================
131
- /// @name Access Methods
132
- ///=============================================================================
133
-
134
- /**
135
- Returns a Boolean value that indicates whether a given key is in cache.
136
-
137
- @param key An object identifying the value. If nil, just return `NO`.
138
- @return Whether the key is in cache.
139
- */
140
- - (BOOL)containsObjectForKey:(id)key;
141
-
142
- /**
143
- Returns the value associated with a given key.
144
-
145
- @param key An object identifying the value. If nil, just return nil.
146
- @return The value associated with key, or nil if no value is associated with key.
147
- */
148
- - (nullable id)objectForKey:(id)key;
149
-
150
- /**
151
- Sets the value of the specified key in the cache (0 cost).
152
-
153
- @param object The object to be stored in the cache. If nil, it calls `removeObjectForKey:`.
154
- @param key The key with which to associate the value. If nil, this method has no effect.
155
- @discussion Unlike an NSMutableDictionary object, a cache does not copy the key
156
- objects that are put into it.
157
- */
158
- - (void)setObject:(nullable id)object forKey:(id)key;
159
-
160
- /**
161
- Sets the value of the specified key in the cache, and associates the key-value
162
- pair with the specified cost.
163
-
164
- @param object The object to store in the cache. If nil, it calls `removeObjectForKey`.
165
- @param key The key with which to associate the value. If nil, this method has no effect.
166
- @param cost The cost with which to associate the key-value pair.
167
- @discussion Unlike an NSMutableDictionary object, a cache does not copy the key
168
- objects that are put into it.
169
- */
170
- - (void)setObject:(nullable id)object forKey:(id)key withCost:(NSUInteger)cost;
171
-
172
- /**
173
- Removes the value of the specified key in the cache.
174
-
175
- @param key The key identifying the value to be removed. If nil, this method has no effect.
176
- */
177
- - (void)removeObjectForKey:(id)key;
178
-
179
- /**
180
- Empties the cache immediately.
181
- */
182
- - (void)removeAllObjects;
183
-
184
-
185
- #pragma mark - Trim
186
- ///=============================================================================
187
- /// @name Trim
188
- ///=============================================================================
189
-
190
- /**
191
- Removes objects from the cache with LRU, until the `totalCount` is below or equal to
192
- the specified value.
193
- @param count The total count allowed to remain after the cache has been trimmed.
194
- */
195
- - (void)trimToCount:(NSUInteger)count;
196
-
197
- /**
198
- Removes objects from the cache with LRU, until the `totalCost` is or equal to
199
- the specified value.
200
- @param cost The total cost allowed to remain after the cache has been trimmed.
201
- */
202
- - (void)trimToCost:(NSUInteger)cost;
203
-
204
- /**
205
- Removes objects from the cache with LRU, until all expiry objects removed by the
206
- specified value.
207
- @param age The maximum age (in seconds) of objects.
208
- */
209
- - (void)trimToAge:(NSTimeInterval)age;
210
-
211
- @end
212
-
213
- NS_ASSUME_NONNULL_END
@@ -1,508 +0,0 @@
1
- //
2
- // YYMemoryCache.m
3
- // YYCache <https://github.com/ibireme/YYCache>
4
- //
5
- // Created by ibireme on 15/2/7.
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
-
12
- #import "YYMemoryCache.h"
13
- #import <UIKit/UIKit.h>
14
- #import <CoreFoundation/CoreFoundation.h>
15
- #import <QuartzCore/QuartzCore.h>
16
- #import <pthread.h>
17
-
18
-
19
- static inline dispatch_queue_t YYMemoryCacheGetReleaseQueue() {
20
- return dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
21
- }
22
-
23
- /**
24
- A node in linked map.
25
- Typically, you should not use this class directly.
26
- */
27
- @interface _YYLinkedMapNode : NSObject {
28
- @package
29
- __unsafe_unretained _YYLinkedMapNode *_prev; // retained by dic
30
- __unsafe_unretained _YYLinkedMapNode *_next; // retained by dic
31
- id _key;
32
- id _value;
33
- NSUInteger _cost;
34
- NSTimeInterval _time;
35
- }
36
- @end
37
-
38
- @implementation _YYLinkedMapNode
39
- @end
40
-
41
-
42
- /**
43
- A linked map used by YYMemoryCache.
44
- It's not thread-safe and does not validate the parameters.
45
-
46
- Typically, you should not use this class directly.
47
- */
48
- @interface _YYLinkedMap : NSObject {
49
- @package
50
- CFMutableDictionaryRef _dic; // do not set object directly
51
- NSUInteger _totalCost;
52
- NSUInteger _totalCount;
53
- _YYLinkedMapNode *_head; // MRU, do not change it directly
54
- _YYLinkedMapNode *_tail; // LRU, do not change it directly
55
- BOOL _releaseOnMainThread;
56
- BOOL _releaseAsynchronously;
57
- }
58
-
59
- /// Insert a node at head and update the total cost.
60
- /// Node and node.key should not be nil.
61
- - (void)insertNodeAtHead:(_YYLinkedMapNode *)node;
62
-
63
- /// Bring a inner node to header.
64
- /// Node should already inside the dic.
65
- - (void)bringNodeToHead:(_YYLinkedMapNode *)node;
66
-
67
- /// Remove a inner node and update the total cost.
68
- /// Node should already inside the dic.
69
- - (void)removeNode:(_YYLinkedMapNode *)node;
70
-
71
- /// Remove tail node if exist.
72
- - (_YYLinkedMapNode *)removeTailNode;
73
-
74
- /// Remove all node in background queue.
75
- - (void)removeAll;
76
-
77
- @end
78
-
79
- @implementation _YYLinkedMap
80
-
81
- - (instancetype)init {
82
- self = [super init];
83
- _dic = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
84
- _releaseOnMainThread = NO;
85
- _releaseAsynchronously = YES;
86
- return self;
87
- }
88
-
89
- - (void)dealloc {
90
- CFRelease(_dic);
91
- }
92
-
93
- - (void)insertNodeAtHead:(_YYLinkedMapNode *)node {
94
- CFDictionarySetValue(_dic, (__bridge const void *)(node->_key), (__bridge const void *)(node));
95
- _totalCost += node->_cost;
96
- _totalCount++;
97
- if (_head) {
98
- node->_next = _head;
99
- _head->_prev = node;
100
- _head = node;
101
- } else {
102
- _head = _tail = node;
103
- }
104
- }
105
-
106
- - (void)bringNodeToHead:(_YYLinkedMapNode *)node {
107
- if (_head == node) return;
108
-
109
- if (_tail == node) {
110
- _tail = node->_prev;
111
- _tail->_next = nil;
112
- } else {
113
- node->_next->_prev = node->_prev;
114
- node->_prev->_next = node->_next;
115
- }
116
- node->_next = _head;
117
- node->_prev = nil;
118
- _head->_prev = node;
119
- _head = node;
120
- }
121
-
122
- - (void)removeNode:(_YYLinkedMapNode *)node {
123
- CFDictionaryRemoveValue(_dic, (__bridge const void *)(node->_key));
124
- _totalCost -= node->_cost;
125
- _totalCount--;
126
- if (node->_next) node->_next->_prev = node->_prev;
127
- if (node->_prev) node->_prev->_next = node->_next;
128
- if (_head == node) _head = node->_next;
129
- if (_tail == node) _tail = node->_prev;
130
- }
131
-
132
- - (_YYLinkedMapNode *)removeTailNode {
133
- if (!_tail) return nil;
134
- _YYLinkedMapNode *tail = _tail;
135
- CFDictionaryRemoveValue(_dic, (__bridge const void *)(_tail->_key));
136
- _totalCost -= _tail->_cost;
137
- _totalCount--;
138
- if (_head == _tail) {
139
- _head = _tail = nil;
140
- } else {
141
- _tail = _tail->_prev;
142
- _tail->_next = nil;
143
- }
144
- return tail;
145
- }
146
-
147
- - (void)removeAll {
148
- _totalCost = 0;
149
- _totalCount = 0;
150
- _head = nil;
151
- _tail = nil;
152
- if (CFDictionaryGetCount(_dic) > 0) {
153
- CFMutableDictionaryRef holder = _dic;
154
- _dic = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
155
-
156
- if (_releaseAsynchronously) {
157
- dispatch_queue_t queue = _releaseOnMainThread ? dispatch_get_main_queue() : YYMemoryCacheGetReleaseQueue();
158
- dispatch_async(queue, ^{
159
- CFRelease(holder); // hold and release in specified queue
160
- });
161
- } else if (_releaseOnMainThread && !pthread_main_np()) {
162
- dispatch_async(dispatch_get_main_queue(), ^{
163
- CFRelease(holder); // hold and release in specified queue
164
- });
165
- } else {
166
- CFRelease(holder);
167
- }
168
- }
169
- }
170
-
171
- @end
172
-
173
-
174
-
175
- @implementation YYMemoryCache {
176
- pthread_mutex_t _lock;
177
- _YYLinkedMap *_lru;
178
- dispatch_queue_t _queue;
179
- }
180
-
181
- - (void)_trimRecursively {
182
- __weak typeof(self) _self = self;
183
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_autoTrimInterval * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
184
- #pragma clang diagnostic push
185
- #pragma clang diagnostic ignored "-Wshadow"
186
- __strong typeof(_self) self = _self;
187
- #pragma clang diagnostic pop
188
- if (!self) return;
189
- [self _trimInBackground];
190
- [self _trimRecursively];
191
- });
192
- }
193
-
194
- - (void)_trimInBackground {
195
- dispatch_async(_queue, ^{
196
- [self _trimToCost:self->_costLimit];
197
- [self _trimToCount:self->_countLimit];
198
- [self _trimToAge:self->_ageLimit];
199
- });
200
- }
201
-
202
- - (void)_trimToCost:(NSUInteger)costLimit {
203
- BOOL finish = NO;
204
- pthread_mutex_lock(&_lock);
205
- if (costLimit == 0) {
206
- [_lru removeAll];
207
- finish = YES;
208
- } else if (_lru->_totalCost <= costLimit) {
209
- finish = YES;
210
- }
211
- pthread_mutex_unlock(&_lock);
212
- if (finish) return;
213
-
214
- NSMutableArray *holder = [NSMutableArray new];
215
- while (!finish) {
216
- if (pthread_mutex_trylock(&_lock) == 0) {
217
- if (_lru->_totalCost > costLimit) {
218
- _YYLinkedMapNode *node = [_lru removeTailNode];
219
- if (node) [holder addObject:node];
220
- } else {
221
- finish = YES;
222
- }
223
- pthread_mutex_unlock(&_lock);
224
- } else {
225
- usleep(10 * 1000); //10 ms
226
- }
227
- }
228
- if (holder.count) {
229
- dispatch_queue_t queue = _lru->_releaseOnMainThread ? dispatch_get_main_queue() : YYMemoryCacheGetReleaseQueue();
230
- dispatch_async(queue, ^{
231
- [holder count]; // release in queue
232
- });
233
- }
234
- }
235
-
236
- - (void)_trimToCount:(NSUInteger)countLimit {
237
- BOOL finish = NO;
238
- pthread_mutex_lock(&_lock);
239
- if (countLimit == 0) {
240
- [_lru removeAll];
241
- finish = YES;
242
- } else if (_lru->_totalCount <= countLimit) {
243
- finish = YES;
244
- }
245
- pthread_mutex_unlock(&_lock);
246
- if (finish) return;
247
-
248
- NSMutableArray *holder = [NSMutableArray new];
249
- while (!finish) {
250
- if (pthread_mutex_trylock(&_lock) == 0) {
251
- if (_lru->_totalCount > countLimit) {
252
- _YYLinkedMapNode *node = [_lru removeTailNode];
253
- if (node) [holder addObject:node];
254
- } else {
255
- finish = YES;
256
- }
257
- pthread_mutex_unlock(&_lock);
258
- } else {
259
- usleep(10 * 1000); //10 ms
260
- }
261
- }
262
- if (holder.count) {
263
- dispatch_queue_t queue = _lru->_releaseOnMainThread ? dispatch_get_main_queue() : YYMemoryCacheGetReleaseQueue();
264
- dispatch_async(queue, ^{
265
- [holder count]; // release in queue
266
- });
267
- }
268
- }
269
-
270
- - (void)_trimToAge:(NSTimeInterval)ageLimit {
271
- BOOL finish = NO;
272
- NSTimeInterval now = CACurrentMediaTime();
273
- pthread_mutex_lock(&_lock);
274
- if (ageLimit <= 0) {
275
- [_lru removeAll];
276
- finish = YES;
277
- } else if (!_lru->_tail || (now - _lru->_tail->_time) <= ageLimit) {
278
- finish = YES;
279
- }
280
- pthread_mutex_unlock(&_lock);
281
- if (finish) return;
282
-
283
- NSMutableArray *holder = [NSMutableArray new];
284
- while (!finish) {
285
- if (pthread_mutex_trylock(&_lock) == 0) {
286
- if (_lru->_tail && (now - _lru->_tail->_time) > ageLimit) {
287
- _YYLinkedMapNode *node = [_lru removeTailNode];
288
- if (node) [holder addObject:node];
289
- } else {
290
- finish = YES;
291
- }
292
- pthread_mutex_unlock(&_lock);
293
- } else {
294
- usleep(10 * 1000); //10 ms
295
- }
296
- }
297
- if (holder.count) {
298
- dispatch_queue_t queue = _lru->_releaseOnMainThread ? dispatch_get_main_queue() : YYMemoryCacheGetReleaseQueue();
299
- dispatch_async(queue, ^{
300
- [holder count]; // release in queue
301
- });
302
- }
303
- }
304
-
305
- - (void)_appDidReceiveMemoryWarningNotification {
306
- if (self.didReceiveMemoryWarningBlock) {
307
- self.didReceiveMemoryWarningBlock(self);
308
- }
309
- if (self.shouldRemoveAllObjectsOnMemoryWarning) {
310
- [self removeAllObjects];
311
- }
312
- }
313
-
314
- - (void)_appDidEnterBackgroundNotification {
315
- if (self.didEnterBackgroundBlock) {
316
- self.didEnterBackgroundBlock(self);
317
- }
318
- if (self.shouldRemoveAllObjectsWhenEnteringBackground) {
319
- [self removeAllObjects];
320
- }
321
- }
322
-
323
- #pragma mark - public
324
-
325
- - (instancetype)init {
326
- self = super.init;
327
- pthread_mutex_init(&_lock, NULL);
328
- _lru = [_YYLinkedMap new];
329
- _queue = dispatch_queue_create("com.ibireme.cache.memory", DISPATCH_QUEUE_SERIAL);
330
-
331
- _countLimit = NSUIntegerMax;
332
- _costLimit = NSUIntegerMax;
333
- _ageLimit = DBL_MAX;
334
- _autoTrimInterval = 5.0;
335
- _shouldRemoveAllObjectsOnMemoryWarning = YES;
336
- _shouldRemoveAllObjectsWhenEnteringBackground = YES;
337
-
338
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_appDidReceiveMemoryWarningNotification) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
339
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_appDidEnterBackgroundNotification) name:UIApplicationDidEnterBackgroundNotification object:nil];
340
-
341
- [self _trimRecursively];
342
- return self;
343
- }
344
-
345
- - (void)dealloc {
346
- [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
347
- [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
348
- [_lru removeAll];
349
- pthread_mutex_destroy(&_lock);
350
- }
351
-
352
- - (NSUInteger)totalCount {
353
- pthread_mutex_lock(&_lock);
354
- NSUInteger count = _lru->_totalCount;
355
- pthread_mutex_unlock(&_lock);
356
- return count;
357
- }
358
-
359
- - (NSUInteger)totalCost {
360
- pthread_mutex_lock(&_lock);
361
- NSUInteger totalCost = _lru->_totalCost;
362
- pthread_mutex_unlock(&_lock);
363
- return totalCost;
364
- }
365
-
366
- - (BOOL)releaseOnMainThread {
367
- pthread_mutex_lock(&_lock);
368
- BOOL releaseOnMainThread = _lru->_releaseOnMainThread;
369
- pthread_mutex_unlock(&_lock);
370
- return releaseOnMainThread;
371
- }
372
-
373
- - (void)setReleaseOnMainThread:(BOOL)releaseOnMainThread {
374
- pthread_mutex_lock(&_lock);
375
- _lru->_releaseOnMainThread = releaseOnMainThread;
376
- pthread_mutex_unlock(&_lock);
377
- }
378
-
379
- - (BOOL)releaseAsynchronously {
380
- pthread_mutex_lock(&_lock);
381
- BOOL releaseAsynchronously = _lru->_releaseAsynchronously;
382
- pthread_mutex_unlock(&_lock);
383
- return releaseAsynchronously;
384
- }
385
-
386
- - (void)setReleaseAsynchronously:(BOOL)releaseAsynchronously {
387
- pthread_mutex_lock(&_lock);
388
- _lru->_releaseAsynchronously = releaseAsynchronously;
389
- pthread_mutex_unlock(&_lock);
390
- }
391
-
392
- - (BOOL)containsObjectForKey:(id)key {
393
- if (!key) return NO;
394
- pthread_mutex_lock(&_lock);
395
- BOOL contains = CFDictionaryContainsKey(_lru->_dic, (__bridge const void *)(key));
396
- pthread_mutex_unlock(&_lock);
397
- return contains;
398
- }
399
-
400
- - (id)objectForKey:(id)key {
401
- if (!key) return nil;
402
- pthread_mutex_lock(&_lock);
403
- _YYLinkedMapNode *node = CFDictionaryGetValue(_lru->_dic, (__bridge const void *)(key));
404
- if (node) {
405
- node->_time = CACurrentMediaTime();
406
- [_lru bringNodeToHead:node];
407
- }
408
- pthread_mutex_unlock(&_lock);
409
- return node ? node->_value : nil;
410
- }
411
-
412
- - (void)setObject:(id)object forKey:(id)key {
413
- [self setObject:object forKey:key withCost:0];
414
- }
415
-
416
- - (void)setObject:(id)object forKey:(id)key withCost:(NSUInteger)cost {
417
- if (!key) return;
418
- if (!object) {
419
- [self removeObjectForKey:key];
420
- return;
421
- }
422
- pthread_mutex_lock(&_lock);
423
- _YYLinkedMapNode *node = CFDictionaryGetValue(_lru->_dic, (__bridge const void *)(key));
424
- NSTimeInterval now = CACurrentMediaTime();
425
- if (node) {
426
- _lru->_totalCost -= node->_cost;
427
- _lru->_totalCost += cost;
428
- node->_cost = cost;
429
- node->_time = now;
430
- node->_value = object;
431
- [_lru bringNodeToHead:node];
432
- } else {
433
- node = [_YYLinkedMapNode new];
434
- node->_cost = cost;
435
- node->_time = now;
436
- node->_key = key;
437
- node->_value = object;
438
- [_lru insertNodeAtHead:node];
439
- }
440
- if (_lru->_totalCost > _costLimit) {
441
- dispatch_async(_queue, ^{
442
- [self trimToCost:self->_costLimit];
443
- });
444
- }
445
- if (_lru->_totalCount > _countLimit) {
446
- _YYLinkedMapNode *linkedMapNode = [_lru removeTailNode];
447
- if (_lru->_releaseAsynchronously) {
448
- dispatch_queue_t queue = _lru->_releaseOnMainThread ? dispatch_get_main_queue() : YYMemoryCacheGetReleaseQueue();
449
- dispatch_async(queue, ^{
450
- [linkedMapNode class]; //hold and release in queue
451
- });
452
- } else if (_lru->_releaseOnMainThread && !pthread_main_np()) {
453
- dispatch_async(dispatch_get_main_queue(), ^{
454
- [linkedMapNode class]; //hold and release in queue
455
- });
456
- }
457
- }
458
- pthread_mutex_unlock(&_lock);
459
- }
460
-
461
- - (void)removeObjectForKey:(id)key {
462
- if (!key) return;
463
- pthread_mutex_lock(&_lock);
464
- _YYLinkedMapNode *node = CFDictionaryGetValue(_lru->_dic, (__bridge const void *)(key));
465
- if (node) {
466
- [_lru removeNode:node];
467
- if (_lru->_releaseAsynchronously) {
468
- dispatch_queue_t queue = _lru->_releaseOnMainThread ? dispatch_get_main_queue() : YYMemoryCacheGetReleaseQueue();
469
- dispatch_async(queue, ^{
470
- [node class]; //hold and release in queue
471
- });
472
- } else if (_lru->_releaseOnMainThread && !pthread_main_np()) {
473
- dispatch_async(dispatch_get_main_queue(), ^{
474
- [node class]; //hold and release in queue
475
- });
476
- }
477
- }
478
- pthread_mutex_unlock(&_lock);
479
- }
480
-
481
- - (void)removeAllObjects {
482
- pthread_mutex_lock(&_lock);
483
- [_lru removeAll];
484
- pthread_mutex_unlock(&_lock);
485
- }
486
-
487
- - (void)trimToCount:(NSUInteger)count {
488
- if (count == 0) {
489
- [self removeAllObjects];
490
- return;
491
- }
492
- [self _trimToCount:count];
493
- }
494
-
495
- - (void)trimToCost:(NSUInteger)cost {
496
- [self _trimToCost:cost];
497
- }
498
-
499
- - (void)trimToAge:(NSTimeInterval)age {
500
- [self _trimToAge:age];
501
- }
502
-
503
- - (NSString *)description {
504
- if (_name) return [NSString stringWithFormat:@"<%@: %p> (%@)", self.class, (void *)self, _name];
505
- else return [NSString stringWithFormat:@"<%@: %p>", self.class, (void *)self];
506
- }
507
-
508
- @end