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.
- package/PrivateHeaders/.DS_Store +0 -0
- package/PrivateHeaders/XCTest/XCTestManager_ManagerInterface-Protocol.h +3 -0
- package/README.md +0 -1
- package/WebDriverAgent.xcodeproj/project.pbxproj +56 -56
- package/WebDriverAgent.xcodeproj/project.xcworkspace/xcuserdata/elf.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/WebDriverAgent.xcodeproj/xcuserdata/elf.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +51 -0
- package/WebDriverAgent.xcodeproj/xcuserdata/{kazuaki.xcuserdatad → elf.xcuserdatad}/xcschemes/xcschememanagement.plist +23 -8
- package/WebDriverAgentLib/.DS_Store +0 -0
- package/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.h +0 -17
- package/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m +0 -16
- package/WebDriverAgentLib/Categories/XCUIElement+FBIsVisible.m +28 -14
- package/WebDriverAgentLib/Categories/XCUIElement+FBResolve.h +37 -0
- package/WebDriverAgentLib/Categories/XCUIElement+FBResolve.m +51 -0
- package/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m +8 -2
- package/WebDriverAgentLib/Commands/FBElementCommands.m +3 -1
- package/WebDriverAgentLib/Commands/FBOrientationCommands.m +20 -9
- package/WebDriverAgentLib/Commands/FBSessionCommands.m +119 -99
- package/WebDriverAgentLib/FBApplication.m +1 -1
- package/WebDriverAgentLib/Routing/FBElementCache.m +42 -11
- package/WebDriverAgentLib/Routing/FBResponsePayload.m +9 -3
- package/WebDriverAgentLib/Routing/FBSession.h +6 -0
- package/WebDriverAgentLib/Routing/FBSession.m +45 -55
- package/WebDriverAgentLib/Utilities/FBAlertsMonitor.h +1 -3
- package/WebDriverAgentLib/Utilities/FBAlertsMonitor.m +6 -13
- package/WebDriverAgentLib/Utilities/FBCapabilities.h +23 -0
- package/WebDriverAgentLib/Utilities/FBCapabilities.m +23 -0
- package/WebDriverAgentLib/Utilities/FBConfiguration.m +6 -1
- package/WebDriverAgentLib/Utilities/FBScreenshot.m +125 -14
- package/WebDriverAgentLib/Utilities/FBSettings.h +23 -23
- package/WebDriverAgentLib/Utilities/FBSettings.m +23 -23
- package/WebDriverAgentLib/Utilities/FBXCodeCompatibility.h +16 -0
- package/WebDriverAgentLib/Utilities/FBXCodeCompatibility.m +16 -0
- package/WebDriverAgentLib/Utilities/FBXPath.m +15 -44
- package/WebDriverAgentLib/Utilities/LRUCache/.DS_Store +0 -0
- package/WebDriverAgentLib/Utilities/LRUCache/LRUCache.h +59 -0
- package/WebDriverAgentLib/Utilities/LRUCache/LRUCache.m +104 -0
- package/WebDriverAgentLib/Utilities/LRUCache/LRUCacheNode.h +43 -0
- package/WebDriverAgentLib/Utilities/LRUCache/LRUCacheNode.m +59 -0
- package/WebDriverAgentLib/Vendor/.DS_Store +0 -0
- package/WebDriverAgentRunner/.DS_Store +0 -0
- package/WebDriverAgentRunner-Runner.app.zip +0 -0
- package/WebDriverAgentTests/IntegrationApp/Resources/.DS_Store +0 -0
- package/WebDriverAgentTests/IntegrationTests/FBSessionIntegrationTests.m +20 -16
- package/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m +2 -1
- package/WebDriverAgentTests/IntegrationTests/XCUIElementFBFindTests.m +11 -0
- package/WebDriverAgentTests/UnitTests/Doubles/FBApplicationDouble.h +3 -0
- package/WebDriverAgentTests/UnitTests/Doubles/FBApplicationDouble.m +15 -0
- package/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.h +1 -0
- package/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.m +1 -0
- package/WebDriverAgentTests/UnitTests/FBSessionTests.m +11 -1
- package/WebDriverAgentTests/UnitTests/FBXPathTests.m +3 -1
- package/WebDriverAgentTests/UnitTests_tvOS/Doubles/XCUIElementDouble.h +1 -0
- package/WebDriverAgentTests/UnitTests_tvOS/Doubles/XCUIElementDouble.m +1 -0
- package/package.json +3 -3
- package/WebDriverAgent.xcodeproj/project.xcworkspace/xcuserdata/kazuaki.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/WebDriverAgent.xcodeproj/project.xcworkspace/xcuserdata/kazuaki.xcuserdatad/WorkspaceSettings.xcsettings +0 -20
- package/WebDriverAgent.xcodeproj/xcuserdata/kazuaki.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +0 -906
- package/WebDriverAgentLib/Vendor/YYCache/YYCache.h +0 -206
- package/WebDriverAgentLib/Vendor/YYCache/YYCache.m +0 -140
- package/WebDriverAgentLib/Vendor/YYCache/YYDiskCache.h +0 -412
- package/WebDriverAgentLib/Vendor/YYCache/YYDiskCache.m +0 -462
- package/WebDriverAgentLib/Vendor/YYCache/YYKVStorage.h +0 -325
- package/WebDriverAgentLib/Vendor/YYCache/YYKVStorage.m +0 -1068
- package/WebDriverAgentLib/Vendor/YYCache/YYMemoryCache.h +0 -213
- 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
|